aiobungie
A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.
Getting Started
This is the basic client you probably want you start with.
import aiobungie
client = aiobungie.Client('YOUR_API_KEY', client_secret='KEY', client_id=0)
async def main() -> None:
async with client.rest:
# Search for Destiny 2 memberships.
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
# Print the user name and their code.
print(f'{user.name} {user.code}')
# aiobungie provides an internal function to run async functions.
# It's equivalent to asyncio.run()
client.run(main()) # or asyncio.run(main())
RESTClient
aiobungie provides a second way to use Bungie's API,
a single RESTClient allows you to make requests and return JSON objects immediately.
This bypasses the need to deserialize and create objects. It also exposes all OAuth2 and manifest methods.
This can be faster for REST apis.
This is considered the core client since aiobungie.Client is built on top of it.
Using the aiobungie.rest property allows direct access to the raw REST client instance.
import aiobungie
import asyncio
client = aiobungie.RESTClient("TOKEN")
async def main() -> None:
async with client as rest:
payload = await rest.fetch_membership('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'])
asyncio.run(main())
RESTPool
A REST client pool allows you to acquire multiple RESTClient that share the same state.
This is useful when you want to spawn an instance for each client which shared the same state.
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def set() -> None:
# Set your ID to access it from other places.
pool.metadata['my_id'] = 4401
async with pool.acquire() as instance:
...
async def fetch() -> None:
my_id: int = pool.metadata['my_id']
async with pool.acquire() as instance: # A different client instance.
my_user = instance.fetch_bungie_user(my_id)
await asyncio.gather(set(), fetch())
When should you use which client?
- Use
Clientwhen you want to build a Chat Bot, Discord Bot, access data as Python classes. - Use
RESTClientwhen you want one TCP session for all clients, access data as JSON payloads. - Use
RESTPoolwhen you're serving a large amount of connections and want to spawn a session for each, access data as JSON payloads. Note that setting up multiple TCP connections can be expensive.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python. 24 25Getting Started 26--------------- 27 28This is the basic client you probably want you start with. 29 30```py 31import aiobungie 32 33client = aiobungie.Client('YOUR_API_KEY', client_secret='KEY', client_id=0) 34 35async def main() -> None: 36 async with client.rest: 37 # Search for Destiny 2 memberships. 38 users = await client.search_users('Crit') 39 40 # Iterate over the users and take the first 5 results. 41 for user in users.take(5): 42 # Print the user name and their code. 43 print(f'{user.name} {user.code}') 44 45# aiobungie provides an internal function to run async functions. 46# It's equivalent to asyncio.run() 47client.run(main()) # or asyncio.run(main()) 48``` 49 50RESTClient 51---------- 52 53aiobungie provides a second way to use Bungie's API, 54 55a single `RESTClient` allows you to make requests and return JSON objects immediately. 56 57This bypasses the need to deserialize and create objects. It also exposes all `OAuth2` and `manifest` methods. 58This can be faster for `REST` apis. 59 60This is considered the core client since `aiobungie.Client` is built on top of it. 61Using the `.rest` property allows direct access to the raw REST client instance. 62 63 64```py 65import aiobungie 66import asyncio 67 68client = aiobungie.RESTClient("TOKEN") 69 70async def main() -> None: 71 async with client as rest: 72 payload = await rest.fetch_membership('Fate怒', 4275) 73 74 for membership in payload: 75 print(membership['membershipId']) 76 77asyncio.run(main()) 78``` 79 80RESTPool 81-------- 82 83A REST client pool allows you to acquire multiple `RESTClient` that share the same state. 84 85This is useful when you want to spawn an instance for each client which shared the same state. 86 87```py 88import aiobungie 89import asyncio 90 91pool = aiobungie.RESTPool("token") 92 93async def set() -> None: 94 # Set your ID to access it from other places. 95 pool.metadata['my_id'] = 4401 96 async with pool.acquire() as instance: 97 ... 98 99async def fetch() -> None: 100 my_id: int = pool.metadata['my_id'] 101 async with pool.acquire() as instance: # A different client instance. 102 my_user = instance.fetch_bungie_user(my_id) 103 104await asyncio.gather(set(), fetch()) 105``` 106 107When should you use which client? 108--------------------------------- 109* Use `Client` when you want to build a Chat Bot, Discord Bot, access data as Python classes. 110* Use `RESTClient` when you want one TCP session for all clients, access data as JSON payloads. 111* Use `RESTPool` when you're serving a large amount of connections and want to spawn a session for each, 112access data as JSON payloads. 113Note that setting up multiple TCP connections can be expensive. 114""" 115 116from __future__ import annotations 117 118from aiobungie import builders 119from aiobungie import crates 120from aiobungie import interfaces 121from aiobungie import traits 122from aiobungie import typedefs 123from aiobungie import url 124from aiobungie.client import Client 125from aiobungie.error import * 126from aiobungie.internal import iterators 127from aiobungie.internal.assets import Image 128from aiobungie.internal.enums import * 129from aiobungie.internal.factory import EmptyFactory 130from aiobungie.internal.factory import Factory 131from aiobungie.internal.iterators import * 132from aiobungie.rest import * 133 134from .metadata import __about__ 135from .metadata import __author__ 136from .metadata import __docs__ 137from .metadata import __email__ 138from .metadata import __license__ 139from .metadata import __url__ 140from .metadata import __version__ 141 142# Alias for crate for backwards compatibility. 143crate = crates 144 145# Activity enums 146from .crates.activity import Difficulty 147 148# Components enums 149from .crates.components import ComponentFields 150from .crates.components import ComponentPrivacy 151 152# Entity enums 153from .crates.entity import GatingScope 154from .crates.entity import ObjectiveUIStyle 155from .crates.entity import ValueUIStyle 156 157# Fireteam enums. 158from .crates.fireteams import FireteamActivity 159from .crates.fireteams import FireteamDate 160from .crates.fireteams import FireteamLanguage 161from .crates.fireteams import FireteamPlatform 162 163# Records enums 164from .crates.records import RecordState 165 166__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
74@attrs.define(auto_exc=True) 75class AiobungieError(RuntimeError): 76 """Base class that all other exceptions inherit from."""
Base class that all other exceptions inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
634@typing.final 635class AmmoType(int, Enum): 636 """AN enum for Detyiny 2 ammo types.""" 637 638 NONE = 0 639 PRIMARY = 1 640 SPECIAL = 2 641 HEAVY = 3
AN enum for Detyiny 2 ammo types.
164@attrs.define(auto_exc=True) 165class BadRequest(HTTPError): 166 """An exception raised when requesting a resource with the provided data is wrong.""" 167 168 url: typedefs.StrOrURL | None 169 """The URL/endpoint caused this error.""" 170 171 body: typing.Any 172 """The response body.""" 173 174 headers: multidict.CIMultiDictProxy[str] 175 """The response headers.""" 176 177 http_status: http.HTTPStatus = attrs.field( 178 default=http.HTTPStatus.BAD_REQUEST, init=False 179 )
An exception raised when requesting a resource with the provided data is wrong.
2def __init__(self, message, url, body, headers): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers)
Method generated by attrs for class BadRequest.
689@typing.final 690class ClanMemberType(int, Enum): 691 """An enum for bungie clan member types.""" 692 693 NONE = 0 694 BEGINNER = 1 695 MEMBER = 2 696 ADMIN = 3 697 ACTING_FOUNDER = 4 698 FOUNDER = 5
An enum for bungie clan member types.
465@typing.final 466class Class(int, Enum): 467 """An Enum for Destiny character classes.""" 468 469 TITAN = 0 470 HUNTER = 1 471 WARLOCK = 2 472 UNKNOWN = 3
An Enum for Destiny character classes.
58class Client(traits.ClientApp): 59 """Standard Bungie API client application. 60 61 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 62 and returns `aiobungie.crates` Python object implementations of the responses. 63 64 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 65 66 Example 67 ------- 68 ```py 69 import aiobungie 70 71 client = aiobungie.Client('...') 72 73 async def main(): 74 async with client.rest: 75 user = await client.fetch_current_user_memberships('...') 76 print(user) 77 ``` 78 79 Parameters 80 ----------- 81 token: `str` 82 Your Bungie's API key or Token from the developer's portal. 83 84 Other Parameters 85 ---------------- 86 max_retries : `int` 87 The max retries number to retry if the request hit a `5xx` status code. 88 client_secret : `str | None` 89 An optional application client secret, 90 This is only needed if you're fetching OAuth2 tokens with this client. 91 client_id : `int | None` 92 An optional application client id, 93 This is only needed if you're fetching OAuth2 tokens with this client. 94 """ 95 96 __slots__ = ("_rest", "_factory") 97 98 def __init__( 99 self, 100 token: str, 101 /, 102 *, 103 client_secret: str | None = None, 104 client_id: int | None = None, 105 max_retries: int = 4, 106 ) -> None: 107 self._rest = rest_.RESTClient( 108 token, 109 client_secret=client_secret, 110 client_id=client_id, 111 max_retries=max_retries, 112 ) 113 114 self._factory = factory_.Factory(self) 115 116 @property 117 def factory(self) -> factory_.Factory: 118 return self._factory 119 120 @property 121 def rest(self) -> interfaces.RESTInterface: 122 return self._rest 123 124 @property 125 def request(self) -> Client: 126 return self 127 128 @property 129 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 130 return self._rest.metadata 131 132 def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None: 133 loop = helpers.get_or_make_loop() 134 135 try: 136 if not loop.is_running(): 137 loop.set_debug(debug) 138 loop.run_until_complete(fn) 139 140 except Exception as exc: 141 raise RuntimeError(f"Failed to run {fn!s}") from exc 142 143 except KeyboardInterrupt: 144 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 145 146 # * User methods. 147 148 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 149 """Fetch and return a user object of the bungie net user associated with account. 150 151 .. warning:: 152 This method requires OAuth2 scope and a Bearer access token. 153 154 Parameters 155 ---------- 156 access_token : `str` 157 A valid Bearer access token for the authorization. 158 159 Returns 160 ------- 161 `aiobungie.crates.user.User` 162 A user object includes the Destiny memberships and Bungie.net user. 163 """ 164 resp = await self.rest.fetch_current_user_memberships(access_token) 165 166 return self.factory.deserialize_user(resp) 167 168 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 169 """Fetch a Bungie user by their BungieNet id. 170 171 .. note:: 172 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 173 for other memberships. 174 175 Parameters 176 ---------- 177 id: `int` 178 The user id. 179 180 Returns 181 ------- 182 `aiobungie.crates.user.BungieUser` 183 A Bungie user. 184 185 Raises 186 ------ 187 `aiobungie.error.NotFound` 188 The user was not found. 189 """ 190 payload = await self.rest.fetch_bungie_user(id) 191 192 return self.factory.deserialize_bungie_user(payload) 193 194 async def search_users( 195 self, name: str, / 196 ) -> iterators.Iterator[user.SearchableDestinyUser]: 197 """Search for players and return all players that matches the same name. 198 199 Parameters 200 ---------- 201 name : `buildins.str` 202 The user name. 203 204 Returns 205 ------- 206 `aiobungie.Iterator[aiobungie.crates.DestinyMembership]` 207 A sequence of destiny memberships. 208 """ 209 payload = await self.rest.search_users(name) 210 211 return iterators.Iterator( 212 [ 213 self.factory.deserialize_searched_user(user) 214 for user in payload["searchResults"] 215 ] 216 ) 217 218 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 219 """Fetch all available user themes. 220 221 Returns 222 ------- 223 `collections.Sequence[aiobungie.crates.user.UserThemes]` 224 A sequence of user themes. 225 """ 226 data = await self.rest.fetch_user_themes() 227 228 return self.factory.deserialize_user_themes(data) 229 230 async def fetch_hard_types( 231 self, 232 credential: int, 233 type: enums.CredentialType | int = enums.CredentialType.STEAMID, 234 /, 235 ) -> user.HardLinkedMembership: 236 """Gets any hard linked membership given a credential. 237 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 238 Cross Save aware. 239 240 Parameters 241 ---------- 242 credential: `int` 243 A valid SteamID64 244 type: `aiobungie.CredentialType` 245 The credential type. This must not be changed 246 Since its only credential that works "currently" 247 248 Returns 249 ------- 250 `aiobungie.crates.user.HardLinkedMembership` 251 Information about the hard linked data. 252 """ 253 254 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 255 256 return user.HardLinkedMembership( 257 id=int(payload["membershipId"]), 258 type=enums.MembershipType(payload["membershipType"]), 259 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 260 ) 261 262 async def fetch_membership_from_id( 263 self, 264 id: int, 265 /, 266 type: enums.MembershipType | int = enums.MembershipType.NONE, 267 ) -> user.User: 268 """Fetch Bungie user's memberships from their id. 269 270 Notes 271 ----- 272 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 273 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 274 see `aiobungie.crates.user.DestinyMembership` for more details. 275 * If you only want the bungie user. Consider using `Client.fetch_user` method. 276 277 Parameters 278 ---------- 279 id : `int` 280 The user's id. 281 type : `aiobungie.MembershipType` 282 The user's membership type. 283 284 Returns 285 ------- 286 `aiobungie.crates.User` 287 A Bungie user with their membership types. 288 289 Raises 290 ------ 291 aiobungie.NotFound 292 The requested user was not found. 293 """ 294 payload = await self.rest.fetch_membership_from_id(id, type) 295 296 return self.factory.deserialize_user(payload) 297 298 async def fetch_user_credentials( 299 self, access_token: str, membership_id: int, / 300 ) -> collections.Sequence[user.UserCredentials]: 301 """Fetch an array of credential types attached to the requested account. 302 303 .. note:: 304 This method require OAuth2 Bearer access token. 305 306 Parameters 307 ---------- 308 access_token : `str` 309 The bearer access token associated with the bungie account. 310 membership_id : `int` 311 The id of the membership to return. 312 313 Returns 314 ------- 315 `collections.Sequence[aiobungie.crates.UserCredentials]` 316 A sequence of the attached user credentials. 317 318 Raises 319 ------ 320 `aiobungie.Unauthorized` 321 The access token was wrong or no access token passed. 322 """ 323 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 324 325 return self.factory.deserialize_user_credentials(resp) 326 327 # * Destiny 2. 328 329 async def fetch_profile( 330 self, 331 member_id: int, 332 type: enums.MembershipType | int, 333 components: list[enums.ComponentType], 334 auth: str | None = None, 335 ) -> components.Component: 336 """ 337 Fetch a bungie profile passing components to the request. 338 339 Parameters 340 ---------- 341 member_id: `int` 342 The member's id. 343 type: `aiobungie.MembershipType` 344 A valid membership type. 345 components : `list[aiobungie.ComponentType]` 346 List of profile components to collect and return. 347 348 Other Parameters 349 ---------------- 350 auth : `str | None` 351 A Bearer access_token to make the request with. 352 This is optional and limited to components that only requires an Authorization token. 353 354 Returns 355 -------- 356 `aiobungie.crates.Component` 357 A Destiny 2 player profile with its components. 358 Only passed components will be available if they exists. Otherwise they will be `None` 359 360 Raises 361 ------ 362 `aiobungie.MembershipTypeError` 363 The provided membership type was invalid. 364 """ 365 data = await self.rest.fetch_profile(member_id, type, components, auth) 366 return self.factory.deserialize_components(data) 367 368 async def fetch_linked_profiles( 369 self, 370 member_id: int, 371 member_type: enums.MembershipType | int, 372 /, 373 *, 374 all: bool = False, 375 ) -> profile.LinkedProfile: 376 """Returns a summary information about all profiles linked to the requested member. 377 378 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 379 380 .. note:: 381 It will only return linked accounts whose linkages you are allowed to view. 382 383 Parameters 384 ---------- 385 member_id : `int` 386 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 387 member_type : `aiobungie.MembershipType` 388 The type for the membership whose linked Destiny account you want to return. 389 390 Other Parameters 391 ---------------- 392 all : `bool` 393 If provided and set to `True`, All memberships regardless 394 of whether they're obscured by overrides will be returned, 395 396 If provided and set to `False`, Only available memberships will be returned. 397 The default for this is `False`. 398 399 Returns 400 ------- 401 `aiobungie.crates.profile.LinkedProfile` 402 A linked profile object. 403 """ 404 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 405 406 return self.factory.deserialize_linked_profiles(resp) 407 408 async def fetch_membership( 409 self, 410 name: str, 411 code: int, 412 /, 413 type: enums.MembershipType | int = enums.MembershipType.ALL, 414 ) -> collections.Sequence[user.DestinyMembership]: 415 """Fetch a Destiny 2 player's memberships. 416 417 Parameters 418 ----------- 419 name: `str` 420 The unique Bungie player name. 421 code : `int` 422 The unique Bungie display name code. 423 type: `aiobungie.internal.enums.MembershipType` 424 The player's membership type, e,g. XBOX, STEAM, PSN 425 426 Returns 427 -------- 428 `collections.Sequence[aiobungie.crates.DestinyMembership]` 429 A sequence of the found Destiny 2 player memberships. 430 An empty sequence will be returned if no one found. 431 432 Raises 433 ------ 434 `aiobungie.MembershipTypeError` 435 The provided membership type was invalid. 436 """ 437 resp = await self.rest.fetch_membership(name, code, type) 438 439 return self.factory.deserialize_destiny_memberships(resp) 440 441 async def fetch_character( 442 self, 443 member_id: int, 444 membership_type: enums.MembershipType | int, 445 character_id: int, 446 components: list[enums.ComponentType], 447 auth: str | None = None, 448 ) -> components.CharacterComponent: 449 """Fetch a Destiny 2 character. 450 451 Parameters 452 ---------- 453 member_id: `int` 454 A valid bungie member id. 455 character_id: `int` 456 The Destiny character id to retrieve. 457 membership_type: `aiobungie.internal.enums.MembershipType` 458 The member's membership type. 459 components: `list[aiobungie.ComponentType]` 460 Multiple arguments of character components to collect and return. 461 462 Other Parameters 463 ---------------- 464 auth : `str | None` 465 A Bearer access_token to make the request with. 466 This is optional and limited to components that only requires an Authorization token. 467 468 Returns 469 ------- 470 `aiobungie.crates.CharacterComponent` 471 A Bungie character component. 472 473 `aiobungie.MembershipTypeError` 474 The provided membership type was invalid. 475 """ 476 resp = await self.rest.fetch_character( 477 member_id, membership_type, character_id, components, auth 478 ) 479 480 return self.factory.deserialize_character_component(resp) 481 482 async def fetch_unique_weapon_history( 483 self, 484 membership_id: int, 485 character_id: int, 486 membership_type: enums.MembershipType | int, 487 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 488 """Fetch details about unique weapon usage for a character. Includes all exotics. 489 490 Parameters 491 ---------- 492 membership_id : `int` 493 The Destiny user membership id. 494 character_id : `int` 495 The character id to retrieve. 496 membership_type : `aiobungie.aiobungie.MembershipType | int` 497 The Destiny user's membership type. 498 499 Returns 500 ------- 501 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 502 A sequence of the weapon's extended values. 503 """ 504 resp = await self._rest.fetch_unique_weapon_history( 505 membership_id, character_id, membership_type 506 ) 507 508 return [ 509 self._factory.deserialize_extended_weapon_values(weapon) 510 for weapon in resp["weapons"] 511 ] 512 513 # * Destiny 2 Activities. 514 515 async def fetch_activities( 516 self, 517 member_id: int, 518 character_id: int, 519 mode: enums.GameMode | int, 520 *, 521 membership_type: enums.MembershipType | int = enums.MembershipType.ALL, 522 page: int = 0, 523 limit: int = 250, 524 ) -> iterators.Iterator[activity.Activity]: 525 """Fetch a Destiny 2 activity for the specified character id. 526 527 Parameters 528 ---------- 529 member_id: `int` 530 The user id that starts with `4611`. 531 character_id: `int` 532 The id of the character to retrieve the activities for. 533 mode: `aiobungie.aiobungie.internal.enums.GameMode | int` 534 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 535 536 Other Parameters 537 ---------------- 538 membership_type: `aiobungie.internal.enums.MembershipType` 539 The Member ship type, if nothing was passed than it will return all. 540 page: int 541 The page number. Default is `0` 542 limit: int 543 Limit the returned result. Default is `250`. 544 545 Returns 546 ------- 547 `aiobungie.Iterator[aiobungie.crates.Activity]` 548 An iterator of the player's activities. 549 550 Raises 551 ------ 552 `aiobungie.MembershipTypeError` 553 The provided membership type was invalid. 554 """ 555 resp = await self.rest.fetch_activities( 556 member_id, 557 character_id, 558 mode, 559 membership_type=membership_type, 560 page=page, 561 limit=limit, 562 ) 563 564 return self.factory.deserialize_activities(resp) 565 566 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 567 """Fetch a post activity details. 568 569 Parameters 570 ---------- 571 instance_id: `int` 572 The activity instance id. 573 574 Returns 575 ------- 576 `aiobungie.crates.PostActivity` 577 A post activity object. 578 """ 579 resp = await self.rest.fetch_post_activity(instance_id) 580 581 return self.factory.deserialize_post_activity(resp) 582 583 async def fetch_aggregated_activity_stats( 584 self, 585 character_id: int, 586 membership_id: int, 587 membership_type: enums.MembershipType | int, 588 ) -> iterators.Iterator[activity.AggregatedActivity]: 589 """Fetch aggregated activity stats for a character. 590 591 Parameters 592 ---------- 593 character_id: `int` 594 The id of the character to retrieve the activities for. 595 membership_id: `int` 596 The id of the user that started with `4611`. 597 membership_type: `aiobungie.internal.enums.MembershipType` 598 The Member ship type. 599 600 Returns 601 ------- 602 `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]` 603 An iterator of the player's activities. 604 605 Raises 606 ------ 607 `aiobungie.MembershipTypeError` 608 The provided membership type was invalid. 609 """ 610 resp = await self.rest.fetch_aggregated_activity_stats( 611 character_id, membership_id, membership_type 612 ) 613 614 return self.factory.deserialize_aggregated_activities(resp) 615 616 # * Destiny 2 Clans or GroupsV2. 617 618 async def fetch_clan_from_id( 619 self, 620 id: int, 621 /, 622 access_token: str | None = None, 623 ) -> clans.Clan: 624 """Fetch a Bungie Clan by its id. 625 626 Parameters 627 ----------- 628 id: `int` 629 The clan id. 630 631 Returns 632 -------- 633 `aiobungie.crates.Clan` 634 An Bungie clan. 635 636 Raises 637 ------ 638 `aiobungie.NotFound` 639 The clan was not found. 640 """ 641 resp = await self.rest.fetch_clan_from_id(id, access_token) 642 643 return self.factory.deserialize_clan(resp) 644 645 async def fetch_clan( 646 self, 647 name: str, 648 /, 649 access_token: str | None = None, 650 *, 651 type: enums.GroupType | int = enums.GroupType.CLAN, 652 ) -> clans.Clan: 653 """Fetch a Clan by its name. 654 This method will return the first clan found with given name. 655 656 Parameters 657 ---------- 658 name: `str` 659 The clan name 660 661 Other Parameters 662 ---------------- 663 access_token : `str | None` 664 An optional access token to make the request with. 665 666 If the token was bound to a member of the clan, 667 This field `aiobungie.crates.Clan.current_user_membership` will be available 668 and will return the membership of the user who made this request. 669 type : `aiobungie.GroupType` 670 The group type, Default is aiobungie.GroupType.CLAN. 671 672 Returns 673 ------- 674 `aiobungie.crates.Clan` 675 A Bungie clan. 676 677 Raises 678 ------ 679 `aiobungie.NotFound` 680 The clan was not found. 681 """ 682 resp = await self.rest.fetch_clan(name, access_token, type=type) 683 684 return self.factory.deserialize_clan(resp) 685 686 async def fetch_clan_conversations( 687 self, clan_id: int, / 688 ) -> collections.Sequence[clans.ClanConversation]: 689 """Fetch the conversations/chat channels of the given clan id. 690 691 Parameters 692 ---------- 693 clan_id : `int` 694 The clan id. 695 696 Returns 697 `collections.Sequence[aiobungie.crates.ClanConversation]` 698 A sequence of the clan chat channels. 699 """ 700 resp = await self.rest.fetch_clan_conversations(clan_id) 701 702 return self.factory.deserialize_clan_conversations(resp) 703 704 async def fetch_clan_admins( 705 self, clan_id: int, / 706 ) -> iterators.Iterator[clans.ClanMember]: 707 """Fetch the clan founder and admins. 708 709 Parameters 710 ---------- 711 clan_id : `int` 712 The clan id. 713 714 Returns 715 ------- 716 `aiobungie.Iterator[aiobungie.crates.ClanMember]` 717 An iterator over the found clan admins and founder. 718 719 Raises 720 ------ 721 `aiobungie.NotFound` 722 The requested clan was not found. 723 """ 724 resp = await self.rest.fetch_clan_admins(clan_id) 725 726 return self.factory.deserialize_clan_members(resp) 727 728 async def fetch_groups_for_member( 729 self, 730 member_id: int, 731 member_type: enums.MembershipType | int, 732 /, 733 *, 734 filter: int = 0, 735 group_type: enums.GroupType = enums.GroupType.CLAN, 736 ) -> collections.Sequence[clans.GroupMember]: 737 """Fetch information about the groups that a given member has joined. 738 739 Parameters 740 ---------- 741 member_id : `int` 742 The member's id 743 member_type : `aiobungie.MembershipType` 744 The member's membership type. 745 746 Other Parameters 747 ---------------- 748 filter : `int` 749 Filter apply to list of joined groups. This Default to `0` 750 group_type : `aiobungie.GroupType` 751 The group's type. 752 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 753 754 Returns 755 ------- 756 `collections.Sequence[aiobungie.crates.GroupMember]` 757 A sequence of joined groups for the fetched member. 758 """ 759 resp = await self.rest.fetch_groups_for_member( 760 member_id, member_type, filter=filter, group_type=group_type 761 ) 762 763 return [ 764 self.factory.deserialize_group_member(group) for group in resp["results"] 765 ] 766 767 async def fetch_potential_groups_for_member( 768 self, 769 member_id: int, 770 member_type: enums.MembershipType | int, 771 /, 772 *, 773 filter: int = 0, 774 group_type: enums.GroupType | int = enums.GroupType.CLAN, 775 ) -> collections.Sequence[clans.GroupMember]: 776 """Fetch the potential groups for a clan member. 777 778 Parameters 779 ---------- 780 member_id : `int` 781 The member's id 782 member_type : `aiobungie.aiobungie.MembershipType | int` 783 The member's membership type. 784 785 Other Parameters 786 ---------------- 787 filter : `int` 788 Filter apply to list of joined groups. This Default to `0` 789 group_type : `aiobungie.aiobungie.GroupType | int` 790 The group's type. 791 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 792 793 Returns 794 ------- 795 `collections.Sequence[aiobungie.crates.GroupMember]` 796 A sequence of joined potential groups for the fetched member. 797 """ 798 resp = await self.rest.fetch_potential_groups_for_member( 799 member_id, member_type, filter=filter, group_type=group_type 800 ) 801 802 return [ 803 self.factory.deserialize_group_member(group) for group in resp["results"] 804 ] 805 806 async def fetch_clan_members( 807 self, 808 clan_id: int, 809 /, 810 *, 811 name: str | None = None, 812 type: enums.MembershipType | int = enums.MembershipType.NONE, 813 ) -> iterators.Iterator[clans.ClanMember]: 814 """Fetch Bungie clan members. 815 816 Parameters 817 ---------- 818 clan_id : `int` 819 The clans id 820 821 Other Parameters 822 ---------------- 823 name : `str | None` 824 If provided, Only players matching this name will be returned. 825 type : `aiobungie.MembershipType` 826 An optional clan member's membership type. 827 This parameter is used to filter the returned results 828 by the provided membership, For an example XBox memberships only, 829 Otherwise will return all memberships. 830 831 Returns 832 ------- 833 `aiobungie.Iterator[aiobungie.crates.ClanMember]` 834 An iterator over the bungie clan members. 835 836 Raises 837 ------ 838 `aiobungie.NotFound` 839 The clan was not found. 840 """ 841 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 842 843 return self.factory.deserialize_clan_members(resp) 844 845 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 846 """Fetch the clan banners. 847 848 Returns 849 ------- 850 `collections.Sequence[aiobungie.crates.ClanBanner]` 851 A sequence of the clan banners. 852 """ 853 resp = await self.rest.fetch_clan_banners() 854 855 return self.factory.deserialize_clan_banners(resp) 856 857 # This method is required to be here since it deserialize the clan. 858 async def kick_clan_member( 859 self, 860 access_token: str, 861 /, 862 group_id: int, 863 membership_id: int, 864 membership_type: enums.MembershipType | int, 865 ) -> clans.Clan: 866 """Kick a member from the clan. 867 868 .. note:: 869 This request requires OAuth2: oauth2: `AdminGroups` scope. 870 871 Parameters 872 ---------- 873 access_token : `str` 874 The bearer access token associated with the bungie account. 875 group_id: `int` 876 The group id. 877 membership_id : `int` 878 The member id to kick. 879 membership_type : `aiobungie.aiobungie.MembershipType | int` 880 The member's membership type. 881 882 Returns 883 ------- 884 `aiobungie.crates.clan.Clan` 885 The clan that the member was kicked from. 886 """ 887 resp = await self.rest.kick_clan_member( 888 access_token, 889 group_id=group_id, 890 membership_id=membership_id, 891 membership_type=membership_type, 892 ) 893 894 return self.factory.deserialize_clan(resp) 895 896 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 897 """Fetch a Bungie clan's weekly reward state. 898 899 Parameters 900 ---------- 901 clan_id : `int` 902 The clan's id. 903 904 Returns 905 ------- 906 `aiobungie.crates.Milestone` 907 A runtime status of the clan's milestone data. 908 """ 909 910 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 911 912 return self.factory.deserialize_milestone(resp) 913 914 # * Destiny 2 Entities aka Definitions. 915 916 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 917 """Fetch a static inventory item entity given a its hash. 918 919 Parameters 920 ---------- 921 hash: `int` 922 Inventory item's hash. 923 924 Returns 925 ------- 926 `aiobungie.crates.InventoryEntity` 927 A bungie inventory item. 928 """ 929 resp = await self.rest.fetch_inventory_item(hash) 930 931 return self.factory.deserialize_inventory_entity(resp) 932 933 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 934 """Fetch a Destiny objective entity given a its hash. 935 936 Parameters 937 ---------- 938 hash: `int` 939 objective's hash. 940 941 Returns 942 ------- 943 `aiobungie.crates.ObjectiveEntity` 944 An objective entity item. 945 """ 946 resp = await self.rest.fetch_objective_entity(hash) 947 948 return self.factory.deserialize_objective_entity(resp) 949 950 async def search_entities( 951 self, name: str, entity_type: str, *, page: int = 0 952 ) -> iterators.Iterator[entity.SearchableEntity]: 953 """Search for Destiny2 entities given a name and its type. 954 955 Parameters 956 ---------- 957 name : `str` 958 The name of the entity, i.e., Thunderlord, One thousand voices. 959 entity_type : `str` 960 The type of the entity, AKA Definition, 961 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 962 963 Other Parameters 964 ---------------- 965 page : `int` 966 An optional page to return. Default to 0. 967 968 Returns 969 ------- 970 `aiobungie.Iterator[aiobungie.crates.SearchableEntity]` 971 An iterator over the found results matching the provided name. 972 """ 973 resp = await self.rest.search_entities(name, entity_type, page=page) 974 975 return self.factory.deserialize_inventory_results(resp) 976 977 # Fireteams 978 979 async def fetch_fireteams( 980 self, 981 activity_type: fireteams.FireteamActivity | int, 982 *, 983 platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY, 984 language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL, 985 date_range: int = 0, 986 page: int = 0, 987 slots_filter: int = 0, 988 ) -> collections.Sequence[fireteams.Fireteam]: 989 """Fetch public Bungie fireteams with open slots. 990 991 Parameters 992 ---------- 993 activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int` 994 The fireteam activity type. 995 996 Other Parameters 997 ---------------- 998 platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int` 999 If this is provided. Then the results will be filtered with the given platform. 1000 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1001 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1002 A locale language to filter the used language in that fireteam. 1003 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1004 date_range : `int` 1005 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1006 page : `int` 1007 The page number. By default its `0` which returns all available activities. 1008 slots_filter : `int` 1009 Filter the returned fireteams based on available slots. Default is `0` 1010 1011 Returns 1012 ------- 1013 `collections.Sequence[fireteams.Fireteam]` 1014 A sequence of `aiobungie.crates.Fireteam`. 1015 """ 1016 1017 resp = await self.rest.fetch_fireteams( 1018 activity_type, 1019 platform=platform, 1020 language=language, 1021 date_range=date_range, 1022 page=page, 1023 slots_filter=slots_filter, 1024 ) 1025 1026 return self.factory.deserialize_fireteams(resp) 1027 1028 async def fetch_available_clan_fireteams( 1029 self, 1030 access_token: str, 1031 group_id: int, 1032 activity_type: fireteams.FireteamActivity | int, 1033 *, 1034 platform: fireteams.FireteamPlatform | int, 1035 language: fireteams.FireteamLanguage | str, 1036 date_range: int = 0, 1037 page: int = 0, 1038 public_only: bool = False, 1039 slots_filter: int = 0, 1040 ) -> collections.Sequence[fireteams.Fireteam]: 1041 """Fetch a clan's fireteams with open slots. 1042 1043 .. note:: 1044 This method requires OAuth2: ReadGroups scope. 1045 1046 Parameters 1047 ---------- 1048 access_token : `str` 1049 The bearer access token associated with the bungie account. 1050 group_id : `int` 1051 The group/clan id of the fireteam. 1052 activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int` 1053 The fireteam activity type. 1054 1055 Other Parameters 1056 ---------------- 1057 platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int` 1058 If this is provided. Then the results will be filtered with the given platform. 1059 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1060 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1061 A locale language to filter the used language in that fireteam. 1062 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1063 date_range : `int` 1064 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1065 page : `int` 1066 The page number. By default its `0` which returns all available activities. 1067 public_only: `bool` 1068 If set to True, Then only public fireteams will be returned. 1069 slots_filter : `int` 1070 Filter the returned fireteams based on available slots. Default is `0` 1071 1072 Returns 1073 ------- 1074 `collections.Sequence[aiobungie.crates.Fireteam]` 1075 A sequence of fireteams found in the clan. 1076 `None` will be returned if nothing was found. 1077 """ 1078 resp = await self.rest.fetch_available_clan_fireteams( 1079 access_token, 1080 group_id, 1081 activity_type, 1082 platform=platform, 1083 language=language, 1084 date_range=date_range, 1085 page=page, 1086 public_only=public_only, 1087 slots_filter=slots_filter, 1088 ) 1089 1090 return self.factory.deserialize_fireteams(resp) 1091 1092 async def fetch_clan_fireteam( 1093 self, access_token: str, fireteam_id: int, group_id: int 1094 ) -> fireteams.AvailableFireteam: 1095 """Fetch a specific clan fireteam. 1096 1097 .. note:: 1098 This method requires OAuth2: ReadGroups scope. 1099 1100 Parameters 1101 ---------- 1102 access_token : `str` 1103 The bearer access token associated with the bungie account. 1104 group_id : `int` 1105 The group/clan id to fetch the fireteam from. 1106 fireteam_id : `int` 1107 The fireteam id to fetch. 1108 1109 Returns 1110 ------- 1111 `aiobungie.crates.AvailableFireteam` 1112 A sequence of available fireteams objects. 1113 """ 1114 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1115 1116 return self.factory.deserialize_available_fireteam(resp) 1117 1118 async def fetch_my_clan_fireteams( 1119 self, 1120 access_token: str, 1121 group_id: int, 1122 *, 1123 include_closed: bool = True, 1124 platform: fireteams.FireteamPlatform | int, 1125 language: fireteams.FireteamLanguage | str, 1126 filtered: bool = True, 1127 page: int = 0, 1128 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1129 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1130 1131 .. note:: 1132 This method requires OAuth2: ReadGroups scope. 1133 1134 Parameters 1135 ---------- 1136 access_token : str 1137 The bearer access token associated with the bungie account. 1138 group_id : int 1139 The group/clan id to fetch. 1140 1141 Other Parameters 1142 ---------------- 1143 include_closed : `bool` 1144 If provided and set to True, It will also return closed fireteams. 1145 If provided and set to False, It will only return public fireteams. Default is True. 1146 platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int 1147 If this is provided. Then the results will be filtered with the given platform. 1148 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1149 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1150 A locale language to filter the used language in that fireteam. 1151 Defaults to aiobungie.crates.FireteamLanguage.ALL 1152 filtered : `bool` 1153 If set to True, it will filter by clan. Otherwise not. Default is True. 1154 page : `int` 1155 The page number. By default its 0 which returns all available activities. 1156 1157 Returns 1158 ------- 1159 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1160 A sequence of available fireteams objects if exists. else `None` will be returned. 1161 """ 1162 resp = await self.rest.fetch_my_clan_fireteams( 1163 access_token, 1164 group_id, 1165 include_closed=include_closed, 1166 platform=platform, 1167 language=language, 1168 filtered=filtered, 1169 page=page, 1170 ) 1171 1172 return self.factory.deserialize_available_fireteams(resp) 1173 1174 # Friends and social. 1175 1176 async def fetch_friends( 1177 self, access_token: str, / 1178 ) -> collections.Sequence[friends.Friend]: 1179 """Fetch bungie friend list. 1180 1181 .. note:: 1182 This requests OAuth2: ReadUserData scope. 1183 1184 Parameters 1185 ----------- 1186 access_token : `str` 1187 The bearer access token associated with the bungie account. 1188 1189 Returns 1190 ------- 1191 `collections.Sequence[aiobungie.crates.Friend]` 1192 A sequence of the friends associated with that access token. 1193 """ 1194 1195 resp = await self.rest.fetch_friends(access_token) 1196 1197 return self.factory.deserialize_friends(resp) 1198 1199 async def fetch_friend_requests( 1200 self, access_token: str, / 1201 ) -> friends.FriendRequestView: 1202 """Fetch pending bungie friend requests queue. 1203 1204 .. note:: 1205 This requests OAuth2: ReadUserData scope. 1206 1207 Parameters 1208 ----------- 1209 access_token : `str` 1210 The bearer access token associated with the bungie account. 1211 1212 Returns 1213 ------- 1214 `aiobungie.crates.FriendRequestView` 1215 A friend requests view of that associated access token. 1216 """ 1217 1218 resp = await self.rest.fetch_friend_requests(access_token) 1219 1220 return self.factory.deserialize_friend_requests(resp) 1221 1222 # Applications and Developer portal. 1223 1224 async def fetch_application(self, appid: int, /) -> application.Application: 1225 """Fetch a Bungie application. 1226 1227 Parameters 1228 ----------- 1229 appid: `int` 1230 The application id. 1231 1232 Returns 1233 -------- 1234 `aiobungie.crates.Application` 1235 A Bungie application. 1236 """ 1237 resp = await self.rest.fetch_application(appid) 1238 1239 return self.factory.deserialize_app(resp) 1240 1241 # Milestones 1242 1243 async def fetch_public_milestone_content( 1244 self, milestone_hash: int, / 1245 ) -> milestones.MilestoneContent: 1246 """Fetch the milestone content given its hash. 1247 1248 Parameters 1249 ---------- 1250 milestone_hash : `int` 1251 The milestone hash. 1252 1253 Returns 1254 ------- 1255 `aiobungie.crates.milestones.MilestoneContent` 1256 A milestone content object. 1257 """ 1258 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1259 1260 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Example
import aiobungie
client = aiobungie.Client('...')
async def main():
async with client.rest:
user = await client.fetch_current_user_memberships('...')
print(user)
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
98 def __init__( 99 self, 100 token: str, 101 /, 102 *, 103 client_secret: str | None = None, 104 client_id: int | None = None, 105 max_retries: int = 4, 106 ) -> None: 107 self._rest = rest_.RESTClient( 108 token, 109 client_secret=client_secret, 110 client_id=client_id, 111 max_retries=max_retries, 112 ) 113 114 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
132 def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None: 133 loop = helpers.get_or_make_loop() 134 135 try: 136 if not loop.is_running(): 137 loop.set_debug(debug) 138 loop.run_until_complete(fn) 139 140 except Exception as exc: 141 raise RuntimeError(f"Failed to run {fn!s}") from exc 142 143 except KeyboardInterrupt: 144 _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- fn (
collections.Awaitable[Any]): The async function to run. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
148 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 149 """Fetch and return a user object of the bungie net user associated with account. 150 151 .. warning:: 152 This method requires OAuth2 scope and a Bearer access token. 153 154 Parameters 155 ---------- 156 access_token : `str` 157 A valid Bearer access token for the authorization. 158 159 Returns 160 ------- 161 `aiobungie.crates.user.User` 162 A user object includes the Destiny memberships and Bungie.net user. 163 """ 164 resp = await self.rest.fetch_current_user_memberships(access_token) 165 166 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
168 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 169 """Fetch a Bungie user by their BungieNet id. 170 171 .. note:: 172 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 173 for other memberships. 174 175 Parameters 176 ---------- 177 id: `int` 178 The user id. 179 180 Returns 181 ------- 182 `aiobungie.crates.user.BungieUser` 183 A Bungie user. 184 185 Raises 186 ------ 187 `aiobungie.error.NotFound` 188 The user was not found. 189 """ 190 payload = await self.rest.fetch_bungie_user(id) 191 192 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
NotFound: The user was not found.
194 async def search_users( 195 self, name: str, / 196 ) -> iterators.Iterator[user.SearchableDestinyUser]: 197 """Search for players and return all players that matches the same name. 198 199 Parameters 200 ---------- 201 name : `buildins.str` 202 The user name. 203 204 Returns 205 ------- 206 `aiobungie.Iterator[aiobungie.crates.DestinyMembership]` 207 A sequence of destiny memberships. 208 """ 209 payload = await self.rest.search_users(name) 210 211 return iterators.Iterator( 212 [ 213 self.factory.deserialize_searched_user(user) 214 for user in payload["searchResults"] 215 ] 216 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.Iterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
218 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 219 """Fetch all available user themes. 220 221 Returns 222 ------- 223 `collections.Sequence[aiobungie.crates.user.UserThemes]` 224 A sequence of user themes. 225 """ 226 data = await self.rest.fetch_user_themes() 227 228 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
230 async def fetch_hard_types( 231 self, 232 credential: int, 233 type: enums.CredentialType | int = enums.CredentialType.STEAMID, 234 /, 235 ) -> user.HardLinkedMembership: 236 """Gets any hard linked membership given a credential. 237 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 238 Cross Save aware. 239 240 Parameters 241 ---------- 242 credential: `int` 243 A valid SteamID64 244 type: `aiobungie.CredentialType` 245 The credential type. This must not be changed 246 Since its only credential that works "currently" 247 248 Returns 249 ------- 250 `aiobungie.crates.user.HardLinkedMembership` 251 Information about the hard linked data. 252 """ 253 254 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 255 256 return user.HardLinkedMembership( 257 id=int(payload["membershipId"]), 258 type=enums.MembershipType(payload["membershipType"]), 259 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 260 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
262 async def fetch_membership_from_id( 263 self, 264 id: int, 265 /, 266 type: enums.MembershipType | int = enums.MembershipType.NONE, 267 ) -> user.User: 268 """Fetch Bungie user's memberships from their id. 269 270 Notes 271 ----- 272 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 273 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 274 see `aiobungie.crates.user.DestinyMembership` for more details. 275 * If you only want the bungie user. Consider using `Client.fetch_user` method. 276 277 Parameters 278 ---------- 279 id : `int` 280 The user's id. 281 type : `aiobungie.MembershipType` 282 The user's membership type. 283 284 Returns 285 ------- 286 `aiobungie.crates.User` 287 A Bungie user with their membership types. 288 289 Raises 290 ------ 291 aiobungie.NotFound 292 The requested user was not found. 293 """ 294 payload = await self.rest.fetch_membership_from_id(id, type) 295 296 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
298 async def fetch_user_credentials( 299 self, access_token: str, membership_id: int, / 300 ) -> collections.Sequence[user.UserCredentials]: 301 """Fetch an array of credential types attached to the requested account. 302 303 .. note:: 304 This method require OAuth2 Bearer access token. 305 306 Parameters 307 ---------- 308 access_token : `str` 309 The bearer access token associated with the bungie account. 310 membership_id : `int` 311 The id of the membership to return. 312 313 Returns 314 ------- 315 `collections.Sequence[aiobungie.crates.UserCredentials]` 316 A sequence of the attached user credentials. 317 318 Raises 319 ------ 320 `aiobungie.Unauthorized` 321 The access token was wrong or no access token passed. 322 """ 323 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 324 325 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
329 async def fetch_profile( 330 self, 331 member_id: int, 332 type: enums.MembershipType | int, 333 components: list[enums.ComponentType], 334 auth: str | None = None, 335 ) -> components.Component: 336 """ 337 Fetch a bungie profile passing components to the request. 338 339 Parameters 340 ---------- 341 member_id: `int` 342 The member's id. 343 type: `aiobungie.MembershipType` 344 A valid membership type. 345 components : `list[aiobungie.ComponentType]` 346 List of profile components to collect and return. 347 348 Other Parameters 349 ---------------- 350 auth : `str | None` 351 A Bearer access_token to make the request with. 352 This is optional and limited to components that only requires an Authorization token. 353 354 Returns 355 -------- 356 `aiobungie.crates.Component` 357 A Destiny 2 player profile with its components. 358 Only passed components will be available if they exists. Otherwise they will be `None` 359 360 Raises 361 ------ 362 `aiobungie.MembershipTypeError` 363 The provided membership type was invalid. 364 """ 365 data = await self.rest.fetch_profile(member_id, type, components, auth) 366 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
368 async def fetch_linked_profiles( 369 self, 370 member_id: int, 371 member_type: enums.MembershipType | int, 372 /, 373 *, 374 all: bool = False, 375 ) -> profile.LinkedProfile: 376 """Returns a summary information about all profiles linked to the requested member. 377 378 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 379 380 .. note:: 381 It will only return linked accounts whose linkages you are allowed to view. 382 383 Parameters 384 ---------- 385 member_id : `int` 386 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 387 member_type : `aiobungie.MembershipType` 388 The type for the membership whose linked Destiny account you want to return. 389 390 Other Parameters 391 ---------------- 392 all : `bool` 393 If provided and set to `True`, All memberships regardless 394 of whether they're obscured by overrides will be returned, 395 396 If provided and set to `False`, Only available memberships will be returned. 397 The default for this is `False`. 398 399 Returns 400 ------- 401 `aiobungie.crates.profile.LinkedProfile` 402 A linked profile object. 403 """ 404 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 405 406 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
408 async def fetch_membership( 409 self, 410 name: str, 411 code: int, 412 /, 413 type: enums.MembershipType | int = enums.MembershipType.ALL, 414 ) -> collections.Sequence[user.DestinyMembership]: 415 """Fetch a Destiny 2 player's memberships. 416 417 Parameters 418 ----------- 419 name: `str` 420 The unique Bungie player name. 421 code : `int` 422 The unique Bungie display name code. 423 type: `aiobungie.internal.enums.MembershipType` 424 The player's membership type, e,g. XBOX, STEAM, PSN 425 426 Returns 427 -------- 428 `collections.Sequence[aiobungie.crates.DestinyMembership]` 429 A sequence of the found Destiny 2 player memberships. 430 An empty sequence will be returned if no one found. 431 432 Raises 433 ------ 434 `aiobungie.MembershipTypeError` 435 The provided membership type was invalid. 436 """ 437 resp = await self.rest.fetch_membership(name, code, type) 438 439 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
441 async def fetch_character( 442 self, 443 member_id: int, 444 membership_type: enums.MembershipType | int, 445 character_id: int, 446 components: list[enums.ComponentType], 447 auth: str | None = None, 448 ) -> components.CharacterComponent: 449 """Fetch a Destiny 2 character. 450 451 Parameters 452 ---------- 453 member_id: `int` 454 A valid bungie member id. 455 character_id: `int` 456 The Destiny character id to retrieve. 457 membership_type: `aiobungie.internal.enums.MembershipType` 458 The member's membership type. 459 components: `list[aiobungie.ComponentType]` 460 Multiple arguments of character components to collect and return. 461 462 Other Parameters 463 ---------------- 464 auth : `str | None` 465 A Bearer access_token to make the request with. 466 This is optional and limited to components that only requires an Authorization token. 467 468 Returns 469 ------- 470 `aiobungie.crates.CharacterComponent` 471 A Bungie character component. 472 473 `aiobungie.MembershipTypeError` 474 The provided membership type was invalid. 475 """ 476 resp = await self.rest.fetch_character( 477 member_id, membership_type, character_id, components, auth 478 ) 479 480 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
482 async def fetch_unique_weapon_history( 483 self, 484 membership_id: int, 485 character_id: int, 486 membership_type: enums.MembershipType | int, 487 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 488 """Fetch details about unique weapon usage for a character. Includes all exotics. 489 490 Parameters 491 ---------- 492 membership_id : `int` 493 The Destiny user membership id. 494 character_id : `int` 495 The character id to retrieve. 496 membership_type : `aiobungie.aiobungie.MembershipType | int` 497 The Destiny user's membership type. 498 499 Returns 500 ------- 501 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 502 A sequence of the weapon's extended values. 503 """ 504 resp = await self._rest.fetch_unique_weapon_history( 505 membership_id, character_id, membership_type 506 ) 507 508 return [ 509 self._factory.deserialize_extended_weapon_values(weapon) 510 for weapon in resp["weapons"] 511 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
515 async def fetch_activities( 516 self, 517 member_id: int, 518 character_id: int, 519 mode: enums.GameMode | int, 520 *, 521 membership_type: enums.MembershipType | int = enums.MembershipType.ALL, 522 page: int = 0, 523 limit: int = 250, 524 ) -> iterators.Iterator[activity.Activity]: 525 """Fetch a Destiny 2 activity for the specified character id. 526 527 Parameters 528 ---------- 529 member_id: `int` 530 The user id that starts with `4611`. 531 character_id: `int` 532 The id of the character to retrieve the activities for. 533 mode: `aiobungie.aiobungie.internal.enums.GameMode | int` 534 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 535 536 Other Parameters 537 ---------------- 538 membership_type: `aiobungie.internal.enums.MembershipType` 539 The Member ship type, if nothing was passed than it will return all. 540 page: int 541 The page number. Default is `0` 542 limit: int 543 Limit the returned result. Default is `250`. 544 545 Returns 546 ------- 547 `aiobungie.Iterator[aiobungie.crates.Activity]` 548 An iterator of the player's activities. 549 550 Raises 551 ------ 552 `aiobungie.MembershipTypeError` 553 The provided membership type was invalid. 554 """ 555 resp = await self.rest.fetch_activities( 556 member_id, 557 character_id, 558 mode, 559 membership_type=membership_type, 560 page=page, 561 limit=limit, 562 ) 563 564 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.aiobungie.internal.enums.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.Iterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
566 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 567 """Fetch a post activity details. 568 569 Parameters 570 ---------- 571 instance_id: `int` 572 The activity instance id. 573 574 Returns 575 ------- 576 `aiobungie.crates.PostActivity` 577 A post activity object. 578 """ 579 resp = await self.rest.fetch_post_activity(instance_id) 580 581 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
583 async def fetch_aggregated_activity_stats( 584 self, 585 character_id: int, 586 membership_id: int, 587 membership_type: enums.MembershipType | int, 588 ) -> iterators.Iterator[activity.AggregatedActivity]: 589 """Fetch aggregated activity stats for a character. 590 591 Parameters 592 ---------- 593 character_id: `int` 594 The id of the character to retrieve the activities for. 595 membership_id: `int` 596 The id of the user that started with `4611`. 597 membership_type: `aiobungie.internal.enums.MembershipType` 598 The Member ship type. 599 600 Returns 601 ------- 602 `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]` 603 An iterator of the player's activities. 604 605 Raises 606 ------ 607 `aiobungie.MembershipTypeError` 608 The provided membership type was invalid. 609 """ 610 resp = await self.rest.fetch_aggregated_activity_stats( 611 character_id, membership_id, membership_type 612 ) 613 614 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
MembershipType): The Member ship type.
Returns
aiobungie.Iterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
618 async def fetch_clan_from_id( 619 self, 620 id: int, 621 /, 622 access_token: str | None = None, 623 ) -> clans.Clan: 624 """Fetch a Bungie Clan by its id. 625 626 Parameters 627 ----------- 628 id: `int` 629 The clan id. 630 631 Returns 632 -------- 633 `aiobungie.crates.Clan` 634 An Bungie clan. 635 636 Raises 637 ------ 638 `aiobungie.NotFound` 639 The clan was not found. 640 """ 641 resp = await self.rest.fetch_clan_from_id(id, access_token) 642 643 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
645 async def fetch_clan( 646 self, 647 name: str, 648 /, 649 access_token: str | None = None, 650 *, 651 type: enums.GroupType | int = enums.GroupType.CLAN, 652 ) -> clans.Clan: 653 """Fetch a Clan by its name. 654 This method will return the first clan found with given name. 655 656 Parameters 657 ---------- 658 name: `str` 659 The clan name 660 661 Other Parameters 662 ---------------- 663 access_token : `str | None` 664 An optional access token to make the request with. 665 666 If the token was bound to a member of the clan, 667 This field `aiobungie.crates.Clan.current_user_membership` will be available 668 and will return the membership of the user who made this request. 669 type : `aiobungie.GroupType` 670 The group type, Default is aiobungie.GroupType.CLAN. 671 672 Returns 673 ------- 674 `aiobungie.crates.Clan` 675 A Bungie clan. 676 677 Raises 678 ------ 679 `aiobungie.NotFound` 680 The clan was not found. 681 """ 682 resp = await self.rest.fetch_clan(name, access_token, type=type) 683 684 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
str | None): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
686 async def fetch_clan_conversations( 687 self, clan_id: int, / 688 ) -> collections.Sequence[clans.ClanConversation]: 689 """Fetch the conversations/chat channels of the given clan id. 690 691 Parameters 692 ---------- 693 clan_id : `int` 694 The clan id. 695 696 Returns 697 `collections.Sequence[aiobungie.crates.ClanConversation]` 698 A sequence of the clan chat channels. 699 """ 700 resp = await self.rest.fetch_clan_conversations(clan_id) 701 702 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
704 async def fetch_clan_admins( 705 self, clan_id: int, / 706 ) -> iterators.Iterator[clans.ClanMember]: 707 """Fetch the clan founder and admins. 708 709 Parameters 710 ---------- 711 clan_id : `int` 712 The clan id. 713 714 Returns 715 ------- 716 `aiobungie.Iterator[aiobungie.crates.ClanMember]` 717 An iterator over the found clan admins and founder. 718 719 Raises 720 ------ 721 `aiobungie.NotFound` 722 The requested clan was not found. 723 """ 724 resp = await self.rest.fetch_clan_admins(clan_id) 725 726 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.Iterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
728 async def fetch_groups_for_member( 729 self, 730 member_id: int, 731 member_type: enums.MembershipType | int, 732 /, 733 *, 734 filter: int = 0, 735 group_type: enums.GroupType = enums.GroupType.CLAN, 736 ) -> collections.Sequence[clans.GroupMember]: 737 """Fetch information about the groups that a given member has joined. 738 739 Parameters 740 ---------- 741 member_id : `int` 742 The member's id 743 member_type : `aiobungie.MembershipType` 744 The member's membership type. 745 746 Other Parameters 747 ---------------- 748 filter : `int` 749 Filter apply to list of joined groups. This Default to `0` 750 group_type : `aiobungie.GroupType` 751 The group's type. 752 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 753 754 Returns 755 ------- 756 `collections.Sequence[aiobungie.crates.GroupMember]` 757 A sequence of joined groups for the fetched member. 758 """ 759 resp = await self.rest.fetch_groups_for_member( 760 member_id, member_type, filter=filter, group_type=group_type 761 ) 762 763 return [ 764 self.factory.deserialize_group_member(group) for group in resp["results"] 765 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
767 async def fetch_potential_groups_for_member( 768 self, 769 member_id: int, 770 member_type: enums.MembershipType | int, 771 /, 772 *, 773 filter: int = 0, 774 group_type: enums.GroupType | int = enums.GroupType.CLAN, 775 ) -> collections.Sequence[clans.GroupMember]: 776 """Fetch the potential groups for a clan member. 777 778 Parameters 779 ---------- 780 member_id : `int` 781 The member's id 782 member_type : `aiobungie.aiobungie.MembershipType | int` 783 The member's membership type. 784 785 Other Parameters 786 ---------------- 787 filter : `int` 788 Filter apply to list of joined groups. This Default to `0` 789 group_type : `aiobungie.aiobungie.GroupType | int` 790 The group's type. 791 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 792 793 Returns 794 ------- 795 `collections.Sequence[aiobungie.crates.GroupMember]` 796 A sequence of joined potential groups for the fetched member. 797 """ 798 resp = await self.rest.fetch_potential_groups_for_member( 799 member_id, member_type, filter=filter, group_type=group_type 800 ) 801 802 return [ 803 self.factory.deserialize_group_member(group) for group in resp["results"] 804 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.aiobungie.GroupType | int): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
806 async def fetch_clan_members( 807 self, 808 clan_id: int, 809 /, 810 *, 811 name: str | None = None, 812 type: enums.MembershipType | int = enums.MembershipType.NONE, 813 ) -> iterators.Iterator[clans.ClanMember]: 814 """Fetch Bungie clan members. 815 816 Parameters 817 ---------- 818 clan_id : `int` 819 The clans id 820 821 Other Parameters 822 ---------------- 823 name : `str | None` 824 If provided, Only players matching this name will be returned. 825 type : `aiobungie.MembershipType` 826 An optional clan member's membership type. 827 This parameter is used to filter the returned results 828 by the provided membership, For an example XBox memberships only, 829 Otherwise will return all memberships. 830 831 Returns 832 ------- 833 `aiobungie.Iterator[aiobungie.crates.ClanMember]` 834 An iterator over the bungie clan members. 835 836 Raises 837 ------ 838 `aiobungie.NotFound` 839 The clan was not found. 840 """ 841 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 842 843 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
str | None): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.Iterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
858 async def kick_clan_member( 859 self, 860 access_token: str, 861 /, 862 group_id: int, 863 membership_id: int, 864 membership_type: enums.MembershipType | int, 865 ) -> clans.Clan: 866 """Kick a member from the clan. 867 868 .. note:: 869 This request requires OAuth2: oauth2: `AdminGroups` scope. 870 871 Parameters 872 ---------- 873 access_token : `str` 874 The bearer access token associated with the bungie account. 875 group_id: `int` 876 The group id. 877 membership_id : `int` 878 The member id to kick. 879 membership_type : `aiobungie.aiobungie.MembershipType | int` 880 The member's membership type. 881 882 Returns 883 ------- 884 `aiobungie.crates.clan.Clan` 885 The clan that the member was kicked from. 886 """ 887 resp = await self.rest.kick_clan_member( 888 access_token, 889 group_id=group_id, 890 membership_id=membership_id, 891 membership_type=membership_type, 892 ) 893 894 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
896 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 897 """Fetch a Bungie clan's weekly reward state. 898 899 Parameters 900 ---------- 901 clan_id : `int` 902 The clan's id. 903 904 Returns 905 ------- 906 `aiobungie.crates.Milestone` 907 A runtime status of the clan's milestone data. 908 """ 909 910 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 911 912 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
916 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 917 """Fetch a static inventory item entity given a its hash. 918 919 Parameters 920 ---------- 921 hash: `int` 922 Inventory item's hash. 923 924 Returns 925 ------- 926 `aiobungie.crates.InventoryEntity` 927 A bungie inventory item. 928 """ 929 resp = await self.rest.fetch_inventory_item(hash) 930 931 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
933 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 934 """Fetch a Destiny objective entity given a its hash. 935 936 Parameters 937 ---------- 938 hash: `int` 939 objective's hash. 940 941 Returns 942 ------- 943 `aiobungie.crates.ObjectiveEntity` 944 An objective entity item. 945 """ 946 resp = await self.rest.fetch_objective_entity(hash) 947 948 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
950 async def search_entities( 951 self, name: str, entity_type: str, *, page: int = 0 952 ) -> iterators.Iterator[entity.SearchableEntity]: 953 """Search for Destiny2 entities given a name and its type. 954 955 Parameters 956 ---------- 957 name : `str` 958 The name of the entity, i.e., Thunderlord, One thousand voices. 959 entity_type : `str` 960 The type of the entity, AKA Definition, 961 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 962 963 Other Parameters 964 ---------------- 965 page : `int` 966 An optional page to return. Default to 0. 967 968 Returns 969 ------- 970 `aiobungie.Iterator[aiobungie.crates.SearchableEntity]` 971 An iterator over the found results matching the provided name. 972 """ 973 resp = await self.rest.search_entities(name, entity_type, page=page) 974 975 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
979 async def fetch_fireteams( 980 self, 981 activity_type: fireteams.FireteamActivity | int, 982 *, 983 platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY, 984 language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL, 985 date_range: int = 0, 986 page: int = 0, 987 slots_filter: int = 0, 988 ) -> collections.Sequence[fireteams.Fireteam]: 989 """Fetch public Bungie fireteams with open slots. 990 991 Parameters 992 ---------- 993 activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int` 994 The fireteam activity type. 995 996 Other Parameters 997 ---------------- 998 platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int` 999 If this is provided. Then the results will be filtered with the given platform. 1000 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1001 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1002 A locale language to filter the used language in that fireteam. 1003 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1004 date_range : `int` 1005 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1006 page : `int` 1007 The page number. By default its `0` which returns all available activities. 1008 slots_filter : `int` 1009 Filter the returned fireteams based on available slots. Default is `0` 1010 1011 Returns 1012 ------- 1013 `collections.Sequence[fireteams.Fireteam]` 1014 A sequence of `aiobungie.crates.Fireteam`. 1015 """ 1016 1017 resp = await self.rest.fetch_fireteams( 1018 activity_type, 1019 platform=platform, 1020 language=language, 1021 date_range=date_range, 1022 page=page, 1023 slots_filter=slots_filter, 1024 ) 1025 1026 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
- platform (
aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
collections.Sequence[fireteams.Fireteam]: A sequence ofaiobungie.crates.Fireteam.
1028 async def fetch_available_clan_fireteams( 1029 self, 1030 access_token: str, 1031 group_id: int, 1032 activity_type: fireteams.FireteamActivity | int, 1033 *, 1034 platform: fireteams.FireteamPlatform | int, 1035 language: fireteams.FireteamLanguage | str, 1036 date_range: int = 0, 1037 page: int = 0, 1038 public_only: bool = False, 1039 slots_filter: int = 0, 1040 ) -> collections.Sequence[fireteams.Fireteam]: 1041 """Fetch a clan's fireteams with open slots. 1042 1043 .. note:: 1044 This method requires OAuth2: ReadGroups scope. 1045 1046 Parameters 1047 ---------- 1048 access_token : `str` 1049 The bearer access token associated with the bungie account. 1050 group_id : `int` 1051 The group/clan id of the fireteam. 1052 activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int` 1053 The fireteam activity type. 1054 1055 Other Parameters 1056 ---------------- 1057 platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int` 1058 If this is provided. Then the results will be filtered with the given platform. 1059 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1060 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1061 A locale language to filter the used language in that fireteam. 1062 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1063 date_range : `int` 1064 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1065 page : `int` 1066 The page number. By default its `0` which returns all available activities. 1067 public_only: `bool` 1068 If set to True, Then only public fireteams will be returned. 1069 slots_filter : `int` 1070 Filter the returned fireteams based on available slots. Default is `0` 1071 1072 Returns 1073 ------- 1074 `collections.Sequence[aiobungie.crates.Fireteam]` 1075 A sequence of fireteams found in the clan. 1076 `None` will be returned if nothing was found. 1077 """ 1078 resp = await self.rest.fetch_available_clan_fireteams( 1079 access_token, 1080 group_id, 1081 activity_type, 1082 platform=platform, 1083 language=language, 1084 date_range=date_range, 1085 page=page, 1086 public_only=public_only, 1087 slots_filter=slots_filter, 1088 ) 1089 1090 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
- platform (
aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1092 async def fetch_clan_fireteam( 1093 self, access_token: str, fireteam_id: int, group_id: int 1094 ) -> fireteams.AvailableFireteam: 1095 """Fetch a specific clan fireteam. 1096 1097 .. note:: 1098 This method requires OAuth2: ReadGroups scope. 1099 1100 Parameters 1101 ---------- 1102 access_token : `str` 1103 The bearer access token associated with the bungie account. 1104 group_id : `int` 1105 The group/clan id to fetch the fireteam from. 1106 fireteam_id : `int` 1107 The fireteam id to fetch. 1108 1109 Returns 1110 ------- 1111 `aiobungie.crates.AvailableFireteam` 1112 A sequence of available fireteams objects. 1113 """ 1114 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1115 1116 return self.factory.deserialize_available_fireteam(resp)
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.crates.AvailableFireteam: A sequence of available fireteams objects.
1118 async def fetch_my_clan_fireteams( 1119 self, 1120 access_token: str, 1121 group_id: int, 1122 *, 1123 include_closed: bool = True, 1124 platform: fireteams.FireteamPlatform | int, 1125 language: fireteams.FireteamLanguage | str, 1126 filtered: bool = True, 1127 page: int = 0, 1128 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1129 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1130 1131 .. note:: 1132 This method requires OAuth2: ReadGroups scope. 1133 1134 Parameters 1135 ---------- 1136 access_token : str 1137 The bearer access token associated with the bungie account. 1138 group_id : int 1139 The group/clan id to fetch. 1140 1141 Other Parameters 1142 ---------------- 1143 include_closed : `bool` 1144 If provided and set to True, It will also return closed fireteams. 1145 If provided and set to False, It will only return public fireteams. Default is True. 1146 platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int 1147 If this is provided. Then the results will be filtered with the given platform. 1148 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1149 language : `aiobungie.crates.fireteams.FireteamLanguage | str` 1150 A locale language to filter the used language in that fireteam. 1151 Defaults to aiobungie.crates.FireteamLanguage.ALL 1152 filtered : `bool` 1153 If set to True, it will filter by clan. Otherwise not. Default is True. 1154 page : `int` 1155 The page number. By default its 0 which returns all available activities. 1156 1157 Returns 1158 ------- 1159 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1160 A sequence of available fireteams objects if exists. else `None` will be returned. 1161 """ 1162 resp = await self.rest.fetch_my_clan_fireteams( 1163 access_token, 1164 group_id, 1165 include_closed=include_closed, 1166 platform=platform, 1167 language=language, 1168 filtered=filtered, 1169 page=page, 1170 ) 1171 1172 return self.factory.deserialize_available_fireteams(resp)
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True. - platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set to True, it will filter by clan. Otherwise not. Default is True. - page (
int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1176 async def fetch_friends( 1177 self, access_token: str, / 1178 ) -> collections.Sequence[friends.Friend]: 1179 """Fetch bungie friend list. 1180 1181 .. note:: 1182 This requests OAuth2: ReadUserData scope. 1183 1184 Parameters 1185 ----------- 1186 access_token : `str` 1187 The bearer access token associated with the bungie account. 1188 1189 Returns 1190 ------- 1191 `collections.Sequence[aiobungie.crates.Friend]` 1192 A sequence of the friends associated with that access token. 1193 """ 1194 1195 resp = await self.rest.fetch_friends(access_token) 1196 1197 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1199 async def fetch_friend_requests( 1200 self, access_token: str, / 1201 ) -> friends.FriendRequestView: 1202 """Fetch pending bungie friend requests queue. 1203 1204 .. note:: 1205 This requests OAuth2: ReadUserData scope. 1206 1207 Parameters 1208 ----------- 1209 access_token : `str` 1210 The bearer access token associated with the bungie account. 1211 1212 Returns 1213 ------- 1214 `aiobungie.crates.FriendRequestView` 1215 A friend requests view of that associated access token. 1216 """ 1217 1218 resp = await self.rest.fetch_friend_requests(access_token) 1219 1220 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1224 async def fetch_application(self, appid: int, /) -> application.Application: 1225 """Fetch a Bungie application. 1226 1227 Parameters 1228 ----------- 1229 appid: `int` 1230 The application id. 1231 1232 Returns 1233 -------- 1234 `aiobungie.crates.Application` 1235 A Bungie application. 1236 """ 1237 resp = await self.rest.fetch_application(appid) 1238 1239 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1243 async def fetch_public_milestone_content( 1244 self, milestone_hash: int, / 1245 ) -> milestones.MilestoneContent: 1246 """Fetch the milestone content given its hash. 1247 1248 Parameters 1249 ---------- 1250 milestone_hash : `int` 1251 The milestone hash. 1252 1253 Returns 1254 ------- 1255 `aiobungie.crates.milestones.MilestoneContent` 1256 A milestone content object. 1257 """ 1258 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1259 1260 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
770@typing.final 771class ClosedReasons(Flag): 772 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 773 774 NONE = 0 775 MATCHMAKING = 1 << 0 776 LOADING = 1 << 1 777 SOLO = 1 << 2 778 """The activity is required to be played solo.""" 779 INTERNAL_REASONS = 1 << 3 780 """ 781 The user can't be joined for one of a variety of internal reasons. 782 Basically, the game can't let you join at this time, 783 but for reasons that aren't under the control of this user 784 """ 785 DISALLOWED_BY_GAME_STATE = 1 << 4 786 """The user's current activity/quest/other transitory game state is preventing joining.""" 787 OFFLINE = 32768 788 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy.NONE 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
347@typing.final 348class ComponentType(Enum): 349 """An Enum for Destiny 2 profile Components.""" 350 351 NONE = 0 352 353 PROFILE = 100 354 PROFILE_INVENTORIES = 102 355 PROFILE_CURRENCIES = 103 356 PROFILE_PROGRESSION = 104 357 ALL_PROFILES = ( 358 PROFILE, 359 PROFILE_INVENTORIES, 360 PROFILE_CURRENCIES, 361 PROFILE_PROGRESSION, 362 ) 363 """All profile components.""" 364 365 VENDORS = 400 366 VENDOR_SALES = 402 367 VENDOR_RECEIPTS = 101 368 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 369 """All vendor components.""" 370 371 # Items 372 ITEM_INSTANCES = 300 373 ITEM_OBJECTIVES = 301 374 ITEM_PERKS = 302 375 ITEM_RENDER_DATA = 303 376 ITEM_STATS = 304 377 ITEM_SOCKETS = 305 378 ITEM_TALENT_GRINDS = 306 379 ITEM_PLUG_STATES = 308 380 ITEM_PLUG_OBJECTIVES = 309 381 ITEM_REUSABLE_PLUGS = 310 382 383 ALL_ITEMS = ( 384 ITEM_PLUG_OBJECTIVES, 385 ITEM_PLUG_STATES, 386 ITEM_SOCKETS, 387 ITEM_INSTANCES, 388 ITEM_OBJECTIVES, 389 ITEM_PERKS, 390 ITEM_RENDER_DATA, 391 ITEM_STATS, 392 ITEM_TALENT_GRINDS, 393 ITEM_REUSABLE_PLUGS, 394 ) 395 """All item components.""" 396 397 PLATFORM_SILVER = 105 398 KIOSKS = 500 399 CURRENCY_LOOKUPS = 600 400 PRESENTATION_NODES = 700 401 COLLECTIBLES = 800 402 RECORDS = 900 403 TRANSITORY = 1000 404 METRICS = 1100 405 INVENTORIES = 102 406 STRING_VARIABLES = 1200 407 CRAFTABLES = 1300 408 409 CHARACTERS = 200 410 CHARACTER_INVENTORY = 201 411 CHARECTER_PROGRESSION = 202 412 CHARACTER_RENDER_DATA = 203 413 CHARACTER_ACTIVITIES = 204 414 CHARACTER_EQUIPMENT = 205 415 CHARACTER_LOADOUTS = 206 416 417 ALL_CHARACTERS = ( 418 CHARACTERS, 419 CHARACTER_INVENTORY, 420 CHARECTER_PROGRESSION, 421 CHARACTER_RENDER_DATA, 422 CHARACTER_ACTIVITIES, 423 CHARACTER_EQUIPMENT, 424 CHARACTER_LOADOUTS, 425 RECORDS, 426 ) 427 """All character components.""" 428 429 ALL = ( 430 *ALL_PROFILES, # type: ignore 431 *ALL_CHARACTERS, # type: ignore 432 *ALL_VENDORS, # type: ignore 433 *ALL_ITEMS, # type: ignore 434 RECORDS, 435 CURRENCY_LOOKUPS, 436 PRESENTATION_NODES, 437 COLLECTIBLES, 438 KIOSKS, 439 METRICS, 440 PLATFORM_SILVER, 441 INVENTORIES, 442 STRING_VARIABLES, 443 TRANSITORY, 444 CRAFTABLES, 445 ) 446 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
652@typing.final 653class CredentialType(int, Enum): 654 """The types of the accounts system supports at bungie.""" 655 656 NONE = 0 657 XUID = 1 658 PSNID = 2 659 WILD = 3 660 FAKE = 4 661 FACEBOOK = 5 662 GOOGLE = 8 663 WINDOWS = 9 664 DEMONID = 10 665 STEAMID = 12 666 BATTLENETID = 14 667 STADIAID = 16 668 TWITCHID = 18
The types of the accounts system supports at bungie.
530@typing.final 531class DamageType(int, Enum): 532 """Enums for Destiny Damage types""" 533 534 NONE = 0 535 KINETIC = 1 536 ARC = 2 537 SOLAR = 3 538 VOID = 4 539 RAID = 5 540 """This is a special damage type reserved for some raid activity encounters.""" 541 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
63@typing.final 64class Difficulty(int, enums.Enum): 65 """An enum for activities difficulties.""" 66 67 TRIVIAL = 0 68 EASY = 1 69 NORMAL = 2 70 CHALLENGING = 3 71 HARD = 4 72 BRAVE = 5 73 ALMOST_IMPOSSIBLE = 6 74 IMPOSSIBLE = 7
An enum for activities difficulties.
149@typing.final 150class Dungeon(int, Enum): 151 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 152 153 NORMAL_PRESAGE = 2124066889 154 """Normal Presage""" 155 156 MASTER_PRESAGE = 4212753278 157 """Master Presage""" 158 159 HARBINGER = 1738383283 160 """Harbinger""" 161 162 PROPHECY = 4148187374 163 """Prophecy""" 164 165 MASTER_POH = 785700673 166 """Master Pit of Heresy?""" 167 168 LEGEND_POH = 785700678 169 """Legend Pit of Heresy?""" 170 171 POH = 1375089621 172 """Normal Pit of Heresy.""" 173 174 SHATTERED = 2032534090 175 """Shattered Throne""" 176 177 GOA_LEGEND = 4078656646 178 """Grasp of Avarice legend.""" 179 180 GOA_MASTER = 3774021532 181 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
2414class EmptyFactory(Factory): 2415 """A stand-alone factory that doesn't requires a client instance. 2416 2417 # Example 2418 --------- 2419 ```py 2420 # We'll implement a serializable RESTClient. 2421 @dataclass(slots=True) 2422 class MyClient(aiobungie.traits.Serializable): 2423 rest = aiobungie.RESTClient(env["CLIENT_TOKEN"]) 2424 my_name = "Fate怒" 2425 my_code = 4275 2426 2427 # Must implement this one method. 2428 @property 2429 def factory(self) -> aiobungie.EmptyFactory: 2430 # Return an empty factory 2431 return aiobungie.EmptyFactory() 2432 2433 async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]: 2434 # Note, Do not call methods within objects, Since this is an empty 2435 # factory, The client reference that makes these calls will be `None`. 2436 response = await self.rest.fetch_membership(self.my_name, self.my_code) 2437 return self.factory.deserialize_destiny_memberships(response) 2438 2439 2440 async def main() -> None: 2441 client = MyClient() 2442 async with client.client: 2443 print(await client.my_memberships()) 2444 2445 asyncio.run(main()) 2446 ``` 2447 """ 2448 2449 __slots__ = () 2450 2451 if typing.TYPE_CHECKING: 2452 # We explicitly want this to be `None`. 2453 _net: None # type: ignore[assignment] 2454 2455 def __init__(self, net: None = None) -> None: 2456 self._net = net
A stand-alone factory that doesn't requires a client instance.
# Example
# We'll implement a serializable RESTClient.
@dataclass(slots=True)
class MyClient(aiobungie.traits.Serializable):
rest = aiobungie.RESTClient(env["CLIENT_TOKEN"])
my_name = "Fate怒"
my_code = 4275
# Must implement this one method.
@property
def factory(self) -> aiobungie.EmptyFactory:
# Return an empty factory
return aiobungie.EmptyFactory()
async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]:
# Note, Do not call methods within objects, Since this is an empty
# factory, The client reference that makes these calls will be `None`.
response = await self.rest.fetch_membership(self.my_name, self.my_code)
return self.factory.deserialize_destiny_memberships(response)
async def main() -> None:
client = MyClient()
async with client.client:
print(await client.my_memberships())
asyncio.run(main())
Inherited Members
- Factory
- deserialize_bungie_user
- deserialize_partial_bungie_user
- deserialize_destiny_membership
- deserialize_destiny_memberships
- deserialize_user
- deserialize_searched_user
- deserialize_user_credentials
- deserialize_user_themes
- deserialize_clan
- deserialize_clan_member
- deserialize_clan_members
- deserialize_group_member
- deserialize_clan_conversations
- deserialize_app_owner
- deserialize_app
- deserialize_profile
- deserialize_profile_item
- deserialize_objectives
- deserialize_records
- deserialize_character_records
- deserialize_character_dye
- deserialize_character_customization
- deserialize_character_minimal_equipments
- deserialize_character_render_data
- deserialize_available_activity
- deserialize_character_activity
- deserialize_profile_items
- deserialize_progressions
- deserialize_milestone
- deserialize_characters
- deserialize_character
- deserialize_character_equipments
- deserialize_character_activities
- deserialize_characters_render_data
- deserialize_character_progressions
- deserialize_character_progressions_mapping
- deserialize_characters_records
- deserialize_profile_records
- deserialize_craftables_component
- deserialize_components
- deserialize_items_component
- deserialize_character_component
- deserialize_inventory_results
- deserialize_inventory_entity
- deserialize_objective_entity
- deserialize_activity
- deserialize_activities
- deserialize_extended_weapon_values
- deserialize_post_activity_player
- deserialize_post_activity
- deserialize_aggregated_activity
- deserialize_aggregated_activities
- deserialize_linked_profiles
- deserialize_public_milestone_content
- deserialize_friend
- deserialize_friends
- deserialize_friend_requests
- deserialize_fireteams
- deserialize_fireteam_destiny_users
- deserialize_fireteam_members
- deserialize_available_fireteam
- deserialize_available_fireteams
- deserialize_fireteam_party
- deserialize_seasonal_artifact
- deserialize_profile_progression
- deserialize_instanced_item
- deserialize_item_energy
- deserialize_item_perk
- deserialize_item_socket
- deserialize_item_stats_view
- deserialize_plug_item_state
69class Enum(__enum.Enum): 70 """Builtin Python enum with extra handlings.""" 71 72 @property 73 def name(self) -> str: # type: ignore[override] 74 return self._name_ 75 76 @property 77 def value(self) -> typing.Any: # type: ignore[override] 78 return self._value_ 79 80 def __str__(self) -> str: 81 return self._name_ 82 83 def __repr__(self) -> str: 84 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 85 86 def __int__(self) -> int: 87 return int(self.value)
Builtin Python enum with extra handlings.
60class Factory(interfaces.FactoryInterface): 61 """The base deserialization factory class for all aiobungie objects. 62 63 This entity factory is used to deserialize JSON responses from the REST client and turning them 64 into a `aiobungie.crates` Python classes. 65 """ 66 67 __slots__ = ("_net",) 68 69 def __init__(self, net: traits.Netrunner) -> None: 70 self._net = net 71 72 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 73 return user.BungieUser( 74 id=int(data["membershipId"]), 75 created_at=time.clean_date(data["firstAccess"]), 76 name=data.get("cachedBungieGlobalDisplayName"), 77 is_deleted=data["isDeleted"], 78 about=data["about"], 79 updated_at=time.clean_date(data["lastUpdate"]), 80 psn_name=data.get("psnDisplayName", None), 81 stadia_name=data.get("stadiaDisplayName", None), 82 steam_name=data.get("steamDisplayName", None), 83 twitch_name=data.get("twitchDisplayName", None), 84 blizzard_name=data.get("blizzardDisplayName", None), 85 status=data["statusText"], 86 locale=data["locale"], 87 picture=assets.Image(path=str(data["profilePicturePath"])), 88 code=data.get("cachedBungieGlobalDisplayNameCode", None), 89 unique_name=data.get("uniqueName", None), 90 theme_id=int(data["profileTheme"]), 91 show_activity=bool(data["showActivity"]), 92 theme_name=data["profileThemeName"], 93 display_title=data["userTitleDisplay"], 94 ) 95 96 def deserialize_partial_bungie_user( 97 self, payload: typedefs.JSONObject 98 ) -> user.PartialBungieUser: 99 return user.PartialBungieUser( 100 net=self._net, 101 types=[ 102 enums.MembershipType(type_) 103 for type_ in payload.get("applicableMembershipTypes", []) 104 ], 105 name=payload.get("displayName"), 106 id=int(payload["membershipId"]), 107 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 108 is_public=payload["isPublic"], 109 icon=assets.Image(payload.get("iconPath", "")), 110 type=enums.MembershipType(payload["membershipType"]), 111 ) 112 113 def deserialize_destiny_membership( 114 self, payload: typedefs.JSONObject 115 ) -> user.DestinyMembership: 116 name: str | None = None 117 if (raw_name := payload.get("bungieGlobalDisplayName")) is not None: 118 name = typedefs.unknown(raw_name) 119 120 return user.DestinyMembership( 121 net=self._net, 122 id=int(payload["membershipId"]), 123 name=name, 124 code=payload.get("bungieGlobalDisplayNameCode", None), 125 last_seen_name=payload.get("LastSeenDisplayName") 126 or payload.get("displayName") # noqa: W503 127 or "", # noqa: W503 128 type=enums.MembershipType(payload["membershipType"]), 129 is_public=payload["isPublic"], 130 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 131 icon=assets.Image(payload.get("iconPath", "")), 132 types=[ 133 enums.MembershipType(type_) 134 for type_ in payload.get("applicableMembershipTypes", []) 135 ], 136 ) 137 138 def deserialize_destiny_memberships( 139 self, data: typedefs.JSONArray 140 ) -> collections.Sequence[user.DestinyMembership]: 141 return [self.deserialize_destiny_membership(membership) for membership in data] 142 143 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 144 primary_membership_id: int | None = None 145 if raw_primary_id := data.get("primaryMembershipId"): 146 primary_membership_id = int(raw_primary_id) 147 148 return user.User( 149 bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]), 150 memberships=self.deserialize_destiny_memberships( 151 data["destinyMemberships"] 152 ), 153 primary_membership_id=primary_membership_id, 154 ) 155 156 def deserialize_searched_user( 157 self, payload: typedefs.JSONObject 158 ) -> user.SearchableDestinyUser: 159 code: int | None = None 160 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 161 code = int(raw_code) 162 163 bungie_id: int | None = None 164 if raw_bungie_id := payload.get("bungieNetMembershipId"): 165 bungie_id = int(raw_bungie_id) 166 167 return user.SearchableDestinyUser( 168 name=typedefs.unknown(payload["bungieGlobalDisplayName"]), 169 code=code, 170 bungie_id=bungie_id, 171 memberships=self.deserialize_destiny_memberships( 172 payload["destinyMemberships"] 173 ), 174 ) 175 176 def deserialize_user_credentials( 177 self, payload: typedefs.JSONArray 178 ) -> collections.Sequence[user.UserCredentials]: 179 return [ 180 user.UserCredentials( 181 type=enums.CredentialType(int(creds["credentialType"])), 182 display_name=creds["credentialDisplayName"], 183 is_public=creds["isPublic"], 184 self_as_string=creds.get("credentialAsString"), 185 ) 186 for creds in payload 187 ] 188 189 def deserialize_user_themes( 190 self, payload: typedefs.JSONArray 191 ) -> collections.Sequence[user.UserThemes]: 192 return [ 193 user.UserThemes( 194 id=int(entry["userThemeId"]), 195 name=entry["userThemeName"] if "userThemeName" in entry else None, 196 description=entry["userThemeDescription"] 197 if "userThemeDescription" in entry 198 else None, 199 ) 200 for entry in payload 201 ] 202 203 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 204 # This is kinda redundant 205 data = payload 206 207 # This is always outside the details. 208 current_user_map: collections.Mapping[str, clans.ClanMember] = {} 209 if raw_current_user_map := payload.get("currentUserMemberMap"): 210 current_user_map = { 211 membership_type: self.deserialize_clan_member(membership) 212 for membership_type, membership in raw_current_user_map.items() 213 } 214 215 try: 216 data = payload["detail"] 217 except KeyError: 218 pass 219 220 id = data["groupId"] 221 name = data["name"] 222 created_at = data["creationDate"] 223 member_count = data["memberCount"] 224 about = data["about"] 225 motto = data["motto"] 226 is_public = data["isPublic"] 227 banner = assets.Image(str(data["bannerPath"])) 228 avatar = assets.Image(str(data["avatarPath"])) 229 tags = data["tags"] 230 type = data["groupType"] 231 232 features = data["features"] 233 features_obj = clans.ClanFeatures( 234 max_members=features["maximumMembers"], 235 max_membership_types=features["maximumMembershipsOfGroupType"], 236 capabilities=features["capabilities"], 237 membership_types=features["membershipTypes"], 238 invite_permissions=features["invitePermissionOverride"], 239 update_banner_permissions=features["updateBannerPermissionOverride"], 240 update_culture_permissions=features["updateCulturePermissionOverride"], 241 join_level=features["joinLevel"], 242 ) 243 244 information: typedefs.JSONObject = data["clanInfo"] 245 progression: collections.Mapping[int, progressions.Progression] = { 246 int(prog_hash): self.deserialize_progressions(prog) 247 for prog_hash, prog in information["d2ClanProgressions"].items() 248 } 249 250 return clans.Clan( 251 net=self._net, 252 id=int(id), 253 name=name, 254 type=enums.GroupType(type), 255 created_at=time.clean_date(created_at), 256 member_count=member_count, 257 motto=motto, 258 about=about, 259 is_public=is_public, 260 banner=banner, 261 avatar=avatar, 262 tags=tags, 263 features=features_obj, 264 owner=self.deserialize_clan_member(payload["founder"]) 265 if "founder" in payload 266 else None, 267 progressions=progression, 268 call_sign=information["clanCallsign"], 269 banner_data=information["clanBannerData"], 270 chat_security=data["chatSecurity"], 271 conversation_id=int(data["conversationId"]), 272 allow_chat=data["allowChat"], 273 theme=data["theme"], 274 current_user_membership=current_user_map, 275 ) 276 277 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 278 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 279 return clans.ClanMember( 280 net=self._net, 281 last_seen_name=destiny_user.last_seen_name, 282 id=destiny_user.id, 283 name=destiny_user.name, 284 icon=destiny_user.icon, 285 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 286 group_id=int(data["groupId"]), 287 joined_at=time.clean_date(data["joinDate"]), 288 types=destiny_user.types, 289 is_public=destiny_user.is_public, 290 type=destiny_user.type, 291 code=destiny_user.code, 292 is_online=data["isOnline"], 293 crossave_override=destiny_user.crossave_override, 294 bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 295 if "bungieNetUserInfo" in data 296 else None, 297 member_type=enums.ClanMemberType(int(data["memberType"])), 298 ) 299 300 def deserialize_clan_members( 301 self, data: typedefs.JSONObject, / 302 ) -> iterators.Iterator[clans.ClanMember]: 303 return iterators.Iterator( 304 [self.deserialize_clan_member(member) for member in data["results"]] 305 ) 306 307 def deserialize_group_member( 308 self, payload: typedefs.JSONObject 309 ) -> clans.GroupMember: 310 member = payload["member"] 311 return clans.GroupMember( 312 net=self._net, 313 join_date=time.clean_date(member["joinDate"]), 314 group_id=int(member["groupId"]), 315 member_type=enums.ClanMemberType(member["memberType"]), 316 is_online=member["isOnline"], 317 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 318 inactive_memberships=payload.get("areAllMembershipsInactive", None), 319 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 320 group=self.deserialize_clan(payload["group"]), 321 ) 322 323 def _deserialize_clan_conversation( 324 self, payload: typedefs.JSONObject 325 ) -> clans.ClanConversation: 326 return clans.ClanConversation( 327 net=self._net, 328 id=int(payload["conversationId"]), 329 group_id=int(payload["groupId"]), 330 name=typedefs.unknown(payload["chatName"]), 331 chat_enabled=payload["chatEnabled"], 332 security=payload["chatSecurity"], 333 ) 334 335 def deserialize_clan_conversations( 336 self, payload: typedefs.JSONArray 337 ) -> collections.Sequence[clans.ClanConversation]: 338 return [self._deserialize_clan_conversation(conv) for conv in payload] 339 340 def deserialize_app_owner( 341 self, payload: typedefs.JSONObject 342 ) -> application.ApplicationOwner: 343 return application.ApplicationOwner( 344 net=self._net, 345 name=payload.get("bungieGlobalDisplayName"), 346 id=int(payload["membershipId"]), 347 type=enums.MembershipType(payload["membershipType"]), 348 icon=assets.Image(str(payload["iconPath"])), 349 is_public=payload["isPublic"], 350 code=payload.get("bungieGlobalDisplayNameCode", None), 351 ) 352 353 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 354 return application.Application( 355 id=int(payload["applicationId"]), 356 name=payload["name"], 357 link=payload["link"], 358 status=payload["status"], 359 redirect_url=payload.get("redirectUrl", None), 360 created_at=time.clean_date(str(payload["creationDate"])), 361 published_at=time.clean_date(str(payload["firstPublished"])), 362 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 363 scope=payload.get("scope"), 364 ) 365 366 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 367 return character.Character( 368 net=self._net, 369 id=int(payload["characterId"]), 370 gender=enums.Gender(payload["genderType"]), 371 race=enums.Race(payload["raceType"]), 372 class_type=enums.Class(payload["classType"]), 373 emblem=assets.Image(payload["emblemBackgroundPath"]) 374 if "emblemBackgroundPath" in payload 375 else None, 376 emblem_icon=assets.Image(payload["emblemPath"]) 377 if "emblemPath" in payload 378 else None, 379 emblem_hash=int(payload["emblemHash"]) if "emblemHash" in payload else None, 380 last_played=time.clean_date(payload["dateLastPlayed"]), 381 total_played_time=int(payload["minutesPlayedTotal"]), 382 member_id=int(payload["membershipId"]), 383 member_type=enums.MembershipType(payload["membershipType"]), 384 level=payload["baseCharacterLevel"], 385 title_hash=payload.get("titleRecordHash", None), 386 light=payload["light"], 387 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 388 ) 389 390 def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile: 391 payload = payload["data"] 392 id = int(payload["userInfo"]["membershipId"]) 393 name = payload["userInfo"]["displayName"] 394 is_public = payload["userInfo"]["isPublic"] 395 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 396 last_played = time.clean_date(str(payload["dateLastPlayed"])) 397 character_ids = [int(cid) for cid in payload["characterIds"]] 398 power_cap = payload["currentSeasonRewardPowerCap"] 399 400 return profile.Profile( 401 id=int(id), 402 name=name, 403 is_public=is_public, 404 type=type, 405 last_played=last_played, 406 character_ids=character_ids, 407 power_cap=power_cap, 408 net=self._net, 409 ) 410 411 def deserialize_profile_item( 412 self, payload: typedefs.JSONObject 413 ) -> profile.ProfileItemImpl: 414 instance_id: int | None = None 415 if raw_instance_id := payload.get("itemInstanceId"): 416 instance_id = int(raw_instance_id) 417 418 version_number: int | None = None 419 if raw_version := payload.get("versionNumber"): 420 version_number = int(raw_version) 421 422 transfer_status = enums.TransferStatus(payload["transferStatus"]) 423 424 return profile.ProfileItemImpl( 425 net=self._net, 426 hash=payload["itemHash"], 427 quantity=payload["quantity"], 428 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 429 location=enums.ItemLocation(payload["location"]), 430 bucket=payload["bucketHash"], 431 transfer_status=transfer_status, 432 lockable=payload["lockable"], 433 state=enums.ItemState(payload["state"]), 434 dismantle_permissions=payload["dismantlePermission"], 435 is_wrapper=payload["isWrapper"], 436 instance_id=instance_id, 437 version_number=version_number, 438 ornament_id=payload.get("overrideStyleItemHash"), 439 ) 440 441 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 442 return records.Objective( 443 net=self._net, 444 hash=payload["objectiveHash"], 445 visible=payload["visible"], 446 complete=payload["complete"], 447 completion_value=payload["completionValue"], 448 progress=payload.get("progress"), 449 destination_hash=payload.get("destinationHash"), 450 activity_hash=payload.get("activityHash"), 451 ) 452 453 # TODO: Remove **nodes and get it directly from the payload. 454 def deserialize_records( 455 self, 456 payload: typedefs.JSONObject, 457 scores: records.RecordScores | None = None, 458 **nodes: int, 459 ) -> records.Record: 460 objectives: list[records.Objective] | None = None 461 interval_objectives: list[records.Objective] | None = None 462 record_state: records.RecordState | int 463 464 record_state = records.RecordState(payload["state"]) 465 466 if raw_objs := payload.get("objectives"): 467 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 468 469 if raw_interval_objs := payload.get("intervalObjectives"): 470 interval_objectives = [ 471 self.deserialize_objectives(obj) for obj in raw_interval_objs 472 ] 473 474 return records.Record( 475 scores=scores, 476 categories_node_hash=nodes.get("categories_hash"), 477 seals_node_hash=nodes.get("seals_hash"), 478 state=record_state, 479 objectives=objectives, 480 interval_objectives=interval_objectives, 481 redeemed_count=payload.get("intervalsRedeemedCount", 0), 482 completion_times=payload.get("completedCount", None), 483 reward_visibility=payload.get("rewardVisibility"), 484 ) 485 486 def deserialize_character_records( 487 self, 488 payload: typedefs.JSONObject, 489 scores: records.RecordScores | None = None, 490 record_hashes: list[int] | None = None, 491 ) -> records.CharacterRecord: 492 record = self.deserialize_records(payload, scores) 493 return records.CharacterRecord( 494 scores=scores, 495 categories_node_hash=record.categories_node_hash, 496 seals_node_hash=record.seals_node_hash, 497 state=record.state, 498 objectives=record.objectives, 499 interval_objectives=record.interval_objectives, 500 redeemed_count=payload.get("intervalsRedeemedCount", 0), 501 completion_times=payload.get("completedCount"), 502 reward_visibility=payload.get("rewardVisibility"), 503 record_hashes=record_hashes or [], 504 ) 505 506 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 507 return character.Dye( 508 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 509 ) 510 511 def deserialize_character_customization( 512 self, payload: typedefs.JSONObject 513 ) -> character.CustomizationOptions: 514 return character.CustomizationOptions( 515 personality=payload["personality"], 516 face=payload["face"], 517 skin_color=payload["skinColor"], 518 lip_color=payload["lipColor"], 519 eye_color=payload["eyeColor"], 520 hair_colors=payload.get("hairColors", []), 521 feature_colors=payload.get("featureColors", []), 522 decal_color=payload["decalColor"], 523 wear_helmet=payload["wearHelmet"], 524 hair_index=payload["hairIndex"], 525 feature_index=payload["featureIndex"], 526 decal_index=payload["decalIndex"], 527 ) 528 529 def deserialize_character_minimal_equipments( 530 self, payload: typedefs.JSONObject 531 ) -> character.MinimalEquipments: 532 if raw_dyes := payload.get("dyes"): 533 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 534 else: 535 dyes = [] 536 537 return character.MinimalEquipments( 538 net=self._net, item_hash=payload["itemHash"], dyes=dyes 539 ) 540 541 def deserialize_character_render_data( 542 self, payload: typedefs.JSONObject, / 543 ) -> character.RenderedData: 544 return character.RenderedData( 545 net=self._net, 546 customization=self.deserialize_character_customization( 547 payload["customization"] 548 ), 549 custom_dyes=[ 550 self.deserialize_character_dye(dye) 551 for dye in payload["customDyes"] 552 if dye 553 ], 554 equipment=[ 555 self.deserialize_character_minimal_equipments(equipment) 556 for equipment in payload["peerView"]["equipment"] 557 ], 558 ) 559 560 def deserialize_available_activity( 561 self, payload: typedefs.JSONObject 562 ) -> activity.AvailableActivity: 563 return activity.AvailableActivity( 564 hash=payload["activityHash"], 565 is_new=payload["isNew"], 566 is_completed=payload["isCompleted"], 567 is_visible=payload["isVisible"], 568 display_level=payload.get("displayLevel"), 569 recommended_light=payload.get("recommendedLight"), 570 difficulty=activity.Difficulty(payload["difficultyTier"]), 571 can_join=payload["canJoin"], 572 can_lead=payload["canLead"], 573 ) 574 575 def deserialize_character_activity( 576 self, payload: typedefs.JSONObject 577 ) -> activity.CharacterActivity: 578 current_mode: enums.GameMode | None = None 579 if raw_current_mode := payload.get("currentActivityModeType"): 580 current_mode = enums.GameMode(raw_current_mode) 581 582 if raw_current_modes := payload.get("currentActivityModeTypes"): 583 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 584 else: 585 current_mode_types = [] 586 587 return activity.CharacterActivity( 588 date_started=time.clean_date(payload["dateActivityStarted"]), 589 current_hash=payload["currentActivityHash"], 590 current_mode_hash=payload["currentActivityModeHash"], 591 current_mode=current_mode, 592 current_mode_hashes=payload.get("currentActivityModeHashes", []), 593 current_mode_types=current_mode_types, 594 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 595 last_story_hash=payload["lastCompletedStoryHash"], 596 available_activities=[ 597 self.deserialize_available_activity(activity_) 598 for activity_ in payload["availableActivities"] 599 ], 600 ) 601 602 def deserialize_profile_items( 603 self, payload: typedefs.JSONObject, / 604 ) -> list[profile.ProfileItemImpl]: 605 return [self.deserialize_profile_item(item) for item in payload["items"]] 606 607 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 608 return records.Node( 609 state=int(payload["state"]), 610 objective=self.deserialize_objectives(payload["objective"]) 611 if "objective" in payload 612 else None, 613 progress_value=int(payload["progressValue"]), 614 completion_value=int(payload["completionValue"]), 615 record_category_score=int(payload["recordCategoryScore"]) 616 if "recordCategoryScore" in payload 617 else None, 618 ) 619 620 @staticmethod 621 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 622 recent_collectibles: collections.Collection[int] | None = None 623 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 624 recent_collectibles = [ 625 int(item_hash) for item_hash in raw_recent_collectibles 626 ] 627 628 collectibles: dict[int, int] = {} 629 for item_hash, mapping in payload["collectibles"].items(): 630 collectibles[int(item_hash)] = int(mapping["state"]) 631 632 return items.Collectible( 633 recent_collectibles=recent_collectibles, 634 collectibles=collectibles, 635 collection_category_hash=int(payload["collectionCategoriesRootNodeHash"]), 636 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 637 ) 638 639 @staticmethod 640 def _deserialize_currencies( 641 payload: typedefs.JSONObject, 642 ) -> collections.Sequence[items.Currency]: 643 return [ 644 items.Currency(hash=int(item_hash), amount=int(amount)) 645 for item_hash, amount in payload["itemQuantities"].items() 646 ] 647 648 def deserialize_progressions( 649 self, payload: typedefs.JSONObject 650 ) -> progressions.Progression: 651 return progressions.Progression( 652 hash=int(payload["progressionHash"]), 653 level=int(payload["level"]), 654 cap=int(payload["levelCap"]), 655 daily_limit=int(payload["dailyLimit"]), 656 weekly_limit=int(payload["weeklyLimit"]), 657 current_progress=int(payload["currentProgress"]), 658 daily_progress=int(payload["dailyProgress"]), 659 needed=int(payload["progressToNextLevel"]), 660 next_level=int(payload["nextLevelAt"]), 661 ) 662 663 def _deserialize_factions( 664 self, payload: typedefs.JSONObject 665 ) -> progressions.Factions: 666 progs = self.deserialize_progressions(payload) 667 return progressions.Factions( 668 hash=progs.hash, 669 level=progs.level, 670 cap=progs.cap, 671 daily_limit=progs.daily_limit, 672 weekly_limit=progs.weekly_limit, 673 current_progress=progs.current_progress, 674 daily_progress=progs.daily_progress, 675 needed=progs.needed, 676 next_level=progs.next_level, 677 faction_hash=payload["factionHash"], 678 faction_vendor_hash=payload["factionVendorIndex"], 679 ) 680 681 def _deserialize_milestone_available_quest( 682 self, payload: typedefs.JSONObject 683 ) -> milestones.MilestoneQuest: 684 return milestones.MilestoneQuest( 685 item_hash=payload["questItemHash"], 686 status=self._deserialize_milestone_quest_status(payload["status"]), 687 ) 688 689 def _deserialize_milestone_activity( 690 self, payload: typedefs.JSONObject 691 ) -> milestones.MilestoneActivity: 692 phases: collections.Sequence[milestones.MilestoneActivityPhase] | None = None 693 if raw_phases := payload.get("phases"): 694 phases = [ 695 milestones.MilestoneActivityPhase( 696 is_completed=obj["complete"], hash=obj["phaseHash"] 697 ) 698 for obj in raw_phases 699 ] 700 701 return milestones.MilestoneActivity( 702 hash=payload["activityHash"], 703 challenges=[ 704 self.deserialize_objectives(obj["objective"]) 705 for obj in payload["challenges"] 706 ], 707 modifier_hashes=payload.get("modifierHashes"), 708 boolean_options=payload.get("booleanActivityOptions"), 709 phases=phases, 710 ) 711 712 def _deserialize_milestone_quest_status( 713 self, payload: typedefs.JSONObject 714 ) -> milestones.QuestStatus: 715 return milestones.QuestStatus( 716 net=self._net, 717 quest_hash=payload["questHash"], 718 step_hash=payload["stepHash"], 719 step_objectives=[ 720 self.deserialize_objectives(objective) 721 for objective in payload["stepObjectives"] 722 ], 723 is_tracked=payload["tracked"], 724 is_completed=payload["completed"], 725 started=payload["started"], 726 item_instance_id=payload["itemInstanceId"], 727 vendor_hash=payload.get("vendorHash"), 728 is_redeemed=payload["redeemed"], 729 ) 730 731 def _deserialize_milestone_rewards( 732 self, payload: typedefs.JSONObject 733 ) -> milestones.MilestoneReward: 734 return milestones.MilestoneReward( 735 category_hash=payload["rewardCategoryHash"], 736 entries=[ 737 milestones.MilestoneRewardEntry( 738 entry_hash=entry["rewardEntryHash"], 739 is_earned=entry["earned"], 740 is_redeemed=entry["redeemed"], 741 ) 742 for entry in payload["entries"] 743 ], 744 ) 745 746 def deserialize_milestone( 747 self, payload: typedefs.JSONObject 748 ) -> milestones.Milestone: 749 start_date: datetime.datetime | None = None 750 if raw_start_date := payload.get("startDate"): 751 start_date = time.clean_date(raw_start_date) 752 753 end_date: datetime.datetime | None = None 754 if raw_end_date := payload.get("endDate"): 755 end_date = time.clean_date(raw_end_date) 756 757 rewards: collections.Collection[milestones.MilestoneReward] | None = None 758 if raw_rewards := payload.get("rewards"): 759 rewards = [ 760 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 761 ] 762 763 activities: collections.Sequence[milestones.MilestoneActivity] | None = None 764 if raw_activities := payload.get("activities"): 765 activities = [ 766 self._deserialize_milestone_activity(active) 767 for active in raw_activities 768 ] 769 770 quests: collections.Sequence[milestones.MilestoneQuest] | None = None 771 if raw_quests := payload.get("availableQuests"): 772 quests = [ 773 self._deserialize_milestone_available_quest(quest) 774 for quest in raw_quests 775 ] 776 777 vendors: collections.Sequence[milestones.MilestoneVendor] | None = None 778 if raw_vendors := payload.get("vendors"): 779 vendors = [ 780 milestones.MilestoneVendor( 781 vendor_hash=vendor["vendorHash"], 782 preview_itemhash=vendor.get("previewItemHash"), 783 ) 784 for vendor in raw_vendors 785 ] 786 787 return milestones.Milestone( 788 hash=payload["milestoneHash"], 789 start_date=start_date, 790 end_date=end_date, 791 order=payload["order"], 792 rewards=rewards, 793 available_quests=quests, 794 activities=activities, 795 vendors=vendors, 796 ) 797 798 def _deserialize_artifact_tiers( 799 self, payload: typedefs.JSONObject 800 ) -> season.ArtifactTier: 801 return season.ArtifactTier( 802 hash=payload["tierHash"], 803 is_unlocked=payload["isUnlocked"], 804 points_to_unlock=payload["pointsToUnlock"], 805 items=[ 806 season.ArtifactTierItem( 807 hash=item["itemHash"], is_active=item["isActive"] 808 ) 809 for item in payload["items"] 810 ], 811 ) 812 813 def deserialize_characters( 814 self, payload: typedefs.JSONObject 815 ) -> collections.Mapping[int, character.Character]: 816 return { 817 int(char_id): self._set_character_attrs(char) 818 for char_id, char in payload["data"].items() 819 } 820 821 def deserialize_character( 822 self, payload: typedefs.JSONObject 823 ) -> character.Character: 824 return self._set_character_attrs(payload) 825 826 def deserialize_character_equipments( 827 self, payload: typedefs.JSONObject 828 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 829 return { 830 int(char_id): self.deserialize_profile_items(item) 831 for char_id, item in payload["data"].items() 832 } 833 834 def deserialize_character_activities( 835 self, payload: typedefs.JSONObject 836 ) -> collections.Mapping[int, activity.CharacterActivity]: 837 return { 838 int(char_id): self.deserialize_character_activity(data) 839 for char_id, data in payload["data"].items() 840 } 841 842 def deserialize_characters_render_data( 843 self, payload: typedefs.JSONObject 844 ) -> collections.Mapping[int, character.RenderedData]: 845 return { 846 int(char_id): self.deserialize_character_render_data(data) 847 for char_id, data in payload["data"].items() 848 } 849 850 def deserialize_character_progressions( 851 self, payload: typedefs.JSONObject 852 ) -> character.CharacterProgression: 853 progressions_ = { 854 int(prog_id): self.deserialize_progressions(prog) 855 for prog_id, prog in payload["progressions"].items() 856 } 857 858 factions = { 859 int(faction_id): self._deserialize_factions(faction) 860 for faction_id, faction in payload["factions"].items() 861 } 862 863 milestones_ = { 864 int(milestone_hash): self.deserialize_milestone(milestone) 865 for milestone_hash, milestone in payload["milestones"].items() 866 } 867 868 uninstanced_item_objectives = { 869 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 870 for item_hash, obj in payload["uninstancedItemObjectives"].items() 871 } 872 873 artifact = payload["seasonalArtifact"] 874 seasonal_artifact = season.CharacterScopedArtifact( 875 hash=artifact["artifactHash"], 876 points_used=artifact["pointsUsed"], 877 reset_count=artifact["resetCount"], 878 tiers=[ 879 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 880 ], 881 ) 882 checklists = payload["checklists"] 883 884 return character.CharacterProgression( 885 progressions=progressions_, 886 factions=factions, 887 checklists=checklists, 888 milestones=milestones_, 889 seasonal_artifact=seasonal_artifact, 890 uninstanced_item_objectives=uninstanced_item_objectives, 891 ) 892 893 def deserialize_character_progressions_mapping( 894 self, payload: typedefs.JSONObject 895 ) -> collections.Mapping[int, character.CharacterProgression]: 896 character_progressions: collections.Mapping[ 897 int, character.CharacterProgression 898 ] = {} 899 for char_id, data in payload["data"].items(): 900 # A little hack to stop mypy complaining about Mapping <-> dict 901 character_progressions[ 902 int(char_id) 903 ] = self.deserialize_character_progressions(data) # type: ignore[index] 904 return character_progressions 905 906 def deserialize_characters_records( 907 self, 908 payload: typedefs.JSONObject, 909 ) -> collections.Mapping[int, records.CharacterRecord]: 910 return { 911 int(rec_id): self.deserialize_character_records( 912 rec, record_hashes=payload.get("featuredRecordHashes") 913 ) 914 for rec_id, rec in payload["records"].items() 915 } 916 917 def deserialize_profile_records( 918 self, payload: typedefs.JSONObject 919 ) -> collections.Mapping[int, records.Record]: 920 raw_profile_records = payload["data"] 921 scores = records.RecordScores( 922 current_score=raw_profile_records["score"], 923 legacy_score=raw_profile_records["legacyScore"], 924 lifetime_score=raw_profile_records["lifetimeScore"], 925 ) 926 return { 927 int(record_id): self.deserialize_records( 928 record, 929 scores, 930 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 931 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 932 ) 933 for record_id, record in raw_profile_records["records"].items() 934 } 935 936 def _deserialize_craftable_socket_plug( 937 self, payload: typedefs.JSONObject 938 ) -> items.CraftableSocketPlug: 939 return items.CraftableSocketPlug( 940 item_hash=int(payload["plugItemHash"]), 941 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 942 ) 943 944 def _deserialize_craftable_socket( 945 self, payload: typedefs.JSONObject 946 ) -> items.CraftableSocket: 947 plugs: list[items.CraftableSocketPlug] = [] 948 if raw_plug := payload.get("plug"): 949 plugs.extend( 950 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 951 ) 952 953 return items.CraftableSocket( 954 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 955 ) 956 957 def _deserialize_craftable_item( 958 self, payload: typedefs.JSONObject 959 ) -> items.CraftableItem: 960 return items.CraftableItem( 961 is_visible=payload["visible"], 962 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 963 sockets=[ 964 self._deserialize_craftable_socket(socket) 965 for socket in payload["sockets"] 966 ], 967 ) 968 969 def deserialize_craftables_component( 970 self, payload: typedefs.JSONObject 971 ) -> components.CraftablesComponent: 972 return components.CraftablesComponent( 973 net=self._net, 974 craftables={ 975 int(item_id): self._deserialize_craftable_item(item) 976 for item_id, item in payload["craftables"].items() 977 if item is not None 978 }, 979 crafting_root_node_hash=payload["craftingRootNodeHash"], 980 ) 981 982 def deserialize_components( # noqa: C901 Too complex. 983 self, payload: typedefs.JSONObject 984 ) -> components.Component: 985 # Due to how complex this method is, We'll stick to 986 # typing.Optional here. 987 988 profile_: profile.Profile | None = None 989 if raw_profile := payload.get("profile"): 990 profile_ = self.deserialize_profile(raw_profile) 991 992 profile_progression: profile.ProfileProgression | None = None 993 if raw_profile_progression := payload.get("profileProgression"): 994 profile_progression = self.deserialize_profile_progression( 995 raw_profile_progression 996 ) 997 998 profile_currencies: typing.Optional[ 999 collections.Sequence[profile.ProfileItemImpl] 1000 ] = None 1001 if raw_profile_currencies := payload.get("profileCurrencies"): 1002 if "data" in raw_profile_currencies: 1003 profile_currencies = self.deserialize_profile_items( 1004 raw_profile_currencies["data"] 1005 ) 1006 1007 profile_inventories: typing.Optional[ 1008 collections.Sequence[profile.ProfileItemImpl] 1009 ] = None 1010 if raw_profile_inventories := payload.get("profileInventory"): 1011 if "data" in raw_profile_inventories: 1012 profile_inventories = self.deserialize_profile_items( 1013 raw_profile_inventories["data"] 1014 ) 1015 1016 profile_records: typing.Optional[ 1017 collections.Mapping[int, records.Record] 1018 ] = None 1019 1020 if raw_profile_records_ := payload.get("profileRecords"): 1021 profile_records = self.deserialize_profile_records(raw_profile_records_) 1022 1023 characters: typing.Optional[ 1024 collections.Mapping[int, character.Character] 1025 ] = None 1026 if raw_characters := payload.get("characters"): 1027 characters = self.deserialize_characters(raw_characters) 1028 1029 character_records: typing.Optional[ 1030 collections.Mapping[int, records.CharacterRecord] 1031 ] = None 1032 1033 if raw_character_records := payload.get("characterRecords"): 1034 # Had to do it in two steps.. 1035 to_update = {} 1036 for _, data in raw_character_records["data"].items(): 1037 for record_id, record in data.items(): 1038 to_update[record_id] = record 1039 1040 character_records = { 1041 int(rec_id): self.deserialize_character_records( 1042 rec, record_hashes=to_update.get("featuredRecordHashes") 1043 ) 1044 for rec_id, rec in to_update["records"].items() 1045 } 1046 1047 character_equipments: typing.Optional[ 1048 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1049 ] = None 1050 if raw_character_equips := payload.get("characterEquipment"): 1051 character_equipments = self.deserialize_character_equipments( 1052 raw_character_equips 1053 ) 1054 1055 character_inventories: typing.Optional[ 1056 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1057 ] = None 1058 if raw_character_inventories := payload.get("characterInventories"): 1059 if "data" in raw_character_inventories: 1060 character_inventories = self.deserialize_character_equipments( 1061 raw_character_inventories 1062 ) 1063 1064 character_activities: typing.Optional[ 1065 collections.Mapping[int, activity.CharacterActivity] 1066 ] = None 1067 if raw_char_acts := payload.get("characterActivities"): 1068 character_activities = self.deserialize_character_activities(raw_char_acts) 1069 1070 character_render_data: typing.Optional[ 1071 collections.Mapping[int, character.RenderedData] 1072 ] = None 1073 if raw_character_render_data := payload.get("characterRenderData"): 1074 character_render_data = self.deserialize_characters_render_data( 1075 raw_character_render_data 1076 ) 1077 1078 character_progressions: typing.Optional[ 1079 collections.Mapping[int, character.CharacterProgression] 1080 ] = None 1081 1082 if raw_character_progressions := payload.get("characterProgressions"): 1083 character_progressions = self.deserialize_character_progressions_mapping( 1084 raw_character_progressions 1085 ) 1086 1087 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1088 if raw_profile_string_vars := payload.get("profileStringVariables"): 1089 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1090 1091 character_string_vars: typing.Optional[ 1092 collections.Mapping[int, collections.Mapping[int, int]] 1093 ] = None 1094 if raw_character_string_vars := payload.get("characterStringVariables"): 1095 character_string_vars = { 1096 int(char_id): data["integerValuesByHash"] 1097 for char_id, data in raw_character_string_vars["data"].items() 1098 } 1099 1100 metrics: typing.Optional[ 1101 collections.Sequence[ 1102 collections.Mapping[int, tuple[bool, records.Objective | None]] 1103 ] 1104 ] = None 1105 root_node_hash: int | None = None 1106 1107 if raw_metrics := payload.get("metrics"): 1108 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1109 metrics = [ 1110 { 1111 int(metrics_hash): ( 1112 data["invisible"], 1113 self.deserialize_objectives(data["objectiveProgress"]) 1114 if "objectiveProgress" in data 1115 else None, 1116 ) 1117 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1118 } 1119 ] 1120 transitory: fireteams.FireteamParty | None = None 1121 if raw_transitory := payload.get("profileTransitoryData"): 1122 if "data" in raw_transitory: 1123 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1124 1125 item_components: components.ItemsComponent | None = None 1126 if raw_item_components := payload.get("itemComponents"): 1127 item_components = self.deserialize_items_component(raw_item_components) 1128 1129 profile_plugsets: typing.Optional[ 1130 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1131 ] = None 1132 1133 if raw_profile_plugs := payload.get("profilePlugSets"): 1134 profile_plugsets = { 1135 int(index): [self.deserialize_plug_item_state(state) for state in data] 1136 for index, data in raw_profile_plugs["data"]["plugs"].items() 1137 } 1138 1139 character_plugsets: typing.Optional[ 1140 collections.Mapping[ 1141 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1142 ] 1143 ] = None 1144 if raw_char_plugsets := payload.get("characterPlugSets"): 1145 character_plugsets = { 1146 int(char_id): { 1147 int(index): [ 1148 self.deserialize_plug_item_state(state) for state in data 1149 ] 1150 for index, data in inner["plugs"].items() 1151 } 1152 for char_id, inner in raw_char_plugsets["data"].items() 1153 } 1154 1155 character_collectibles: typing.Optional[ 1156 collections.Mapping[int, items.Collectible] 1157 ] = None 1158 if raw_character_collectibles := payload.get("characterCollectibles"): 1159 character_collectibles = { 1160 int(char_id): self._deserialize_collectible(data) 1161 for char_id, data in raw_character_collectibles["data"].items() 1162 } 1163 1164 profile_collectibles: items.Collectible | None = None 1165 if raw_profile_collectibles := payload.get("profileCollectibles"): 1166 profile_collectibles = self._deserialize_collectible( 1167 raw_profile_collectibles["data"] 1168 ) 1169 1170 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1171 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1172 profile_nodes = { 1173 int(node_hash): self._deserialize_node(node) 1174 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1175 } 1176 1177 character_nodes: typing.Optional[ 1178 collections.Mapping[int, collections.Mapping[int, records.Node]] 1179 ] = None 1180 if raw_character_nodes := payload.get("characterPresentationNodes"): 1181 character_nodes = { 1182 int(char_id): { 1183 int(node_hash): self._deserialize_node(node) 1184 for node_hash, node in each_character["nodes"].items() 1185 } 1186 for char_id, each_character in raw_character_nodes["data"].items() 1187 } 1188 1189 platform_silver: typing.Optional[ 1190 collections.Mapping[str, profile.ProfileItemImpl] 1191 ] = None 1192 if raw_platform_silver := payload.get("platformSilver"): 1193 if "data" in raw_platform_silver: 1194 platform_silver = { 1195 platform_name: self.deserialize_profile_item(item) 1196 for platform_name, item in raw_platform_silver["data"][ 1197 "platformSilver" 1198 ].items() 1199 } 1200 1201 character_currency_lookups: typing.Optional[ 1202 collections.Mapping[int, collections.Sequence[items.Currency]] 1203 ] = None 1204 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1205 if "data" in raw_char_lookups: 1206 character_currency_lookups = { 1207 int(char_id): self._deserialize_currencies(currency) 1208 for char_id, currency in raw_char_lookups["data"].items() 1209 } 1210 1211 character_craftables: typing.Optional[ 1212 collections.Mapping[int, components.CraftablesComponent] 1213 ] = None 1214 if raw_character_craftables := payload.get("characterCraftables"): 1215 if "data" in raw_character_craftables: 1216 character_craftables = { 1217 int(char_id): self.deserialize_craftables_component(craftable) 1218 for char_id, craftable in raw_character_craftables["data"].items() 1219 } 1220 1221 return components.Component( 1222 profiles=profile_, 1223 profile_progression=profile_progression, 1224 profile_currencies=profile_currencies, 1225 profile_inventories=profile_inventories, 1226 profile_records=profile_records, 1227 characters=characters, 1228 character_records=character_records, 1229 character_equipments=character_equipments, 1230 character_inventories=character_inventories, 1231 character_activities=character_activities, 1232 character_render_data=character_render_data, 1233 character_progressions=character_progressions, 1234 profile_string_variables=profile_string_vars, 1235 character_string_variables=character_string_vars, 1236 metrics=metrics, 1237 root_node_hash=root_node_hash, 1238 transitory=transitory, 1239 item_components=item_components, 1240 profile_plugsets=profile_plugsets, 1241 character_plugsets=character_plugsets, 1242 character_collectibles=character_collectibles, 1243 profile_collectibles=profile_collectibles, 1244 profile_nodes=profile_nodes, 1245 character_nodes=character_nodes, 1246 platform_silver=platform_silver, 1247 character_currency_lookups=character_currency_lookups, 1248 character_craftables=character_craftables, 1249 ) 1250 1251 def deserialize_items_component( 1252 self, payload: typedefs.JSONObject 1253 ) -> components.ItemsComponent: 1254 # Due to how complex this method is, We'll stick to typing.Optional. 1255 instances: typing.Optional[ 1256 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1257 ] = None 1258 if raw_instances := payload.get("instances"): 1259 instances = [ 1260 { 1261 int(ins_id): self.deserialize_instanced_item(item) 1262 for ins_id, item in raw_instances["data"].items() 1263 } 1264 ] 1265 1266 render_data: typing.Optional[ 1267 collections.Mapping[int, tuple[bool, dict[int, int]]] 1268 ] = None 1269 if raw_render_data := payload.get("renderData"): 1270 render_data = { 1271 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1272 for ins_id, data in raw_render_data["data"].items() 1273 } 1274 1275 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1276 if raw_stats := payload.get("stats"): 1277 builder: collections.Mapping[int, items.ItemStatsView] = {} 1278 for ins_id, stat in raw_stats["data"].items(): 1279 for _, items_ in stat.items(): 1280 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1281 stats = builder 1282 1283 sockets: typing.Optional[ 1284 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1285 ] = None 1286 if raw_sockets := payload.get("sockets"): 1287 sockets = { 1288 int(ins_id): [ 1289 self.deserialize_item_socket(socket) for socket in item["sockets"] 1290 ] 1291 for ins_id, item in raw_sockets["data"].items() 1292 } 1293 1294 objectives: typing.Optional[ 1295 collections.Mapping[int, collections.Sequence[records.Objective]] 1296 ] = None 1297 if raw_objectives := payload.get("objectives"): 1298 objectives = { 1299 int(ins_id): [self.deserialize_objectives(objective)] 1300 for ins_id, data in raw_objectives["data"].items() 1301 for objective in data["objectives"] 1302 } 1303 1304 perks: typing.Optional[ 1305 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1306 ] = None 1307 if raw_perks := payload.get("perks"): 1308 perks = { 1309 int(ins_id): [ 1310 self.deserialize_item_perk(perk) for perk in item["perks"] 1311 ] 1312 for ins_id, item in raw_perks["data"].items() 1313 } 1314 1315 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1316 if raw_plug_states := payload.get("plugStates"): 1317 pending_states: list[items.PlugItemState] = [] 1318 for _, plug in raw_plug_states["data"].items(): 1319 pending_states.append(self.deserialize_plug_item_state(plug)) 1320 plug_states = pending_states 1321 1322 reusable_plugs: typing.Optional[ 1323 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1324 ] = None 1325 if raw_re_plugs := payload.get("reusablePlugs"): 1326 reusable_plugs = { 1327 int(ins_id): [ 1328 self.deserialize_plug_item_state(state) for state in inner 1329 ] 1330 for ins_id, plug in raw_re_plugs["data"].items() 1331 for inner in list(plug["plugs"].values()) 1332 } 1333 1334 plug_objectives: typing.Optional[ 1335 collections.Mapping[ 1336 int, collections.Mapping[int, collections.Collection[records.Objective]] 1337 ] 1338 ] = None 1339 if raw_plug_objectives := payload.get("plugObjectives"): 1340 plug_objectives = { 1341 int(ins_id): { 1342 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1343 for obj_hash, objs in inner["objectivesPerPlug"].items() 1344 } 1345 for ins_id, inner in raw_plug_objectives["data"].items() 1346 } 1347 1348 return components.ItemsComponent( 1349 sockets=sockets, 1350 stats=stats, 1351 render_data=render_data, 1352 instances=instances, 1353 objectives=objectives, 1354 perks=perks, 1355 plug_states=plug_states, 1356 reusable_plugs=reusable_plugs, 1357 plug_objectives=plug_objectives, 1358 ) 1359 1360 def deserialize_character_component( # type: ignore[call-arg] 1361 self, payload: typedefs.JSONObject 1362 ) -> components.CharacterComponent: 1363 character_: character.Character | None = None 1364 if raw_singular_character := payload.get("character"): 1365 character_ = self.deserialize_character(raw_singular_character["data"]) 1366 1367 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1368 if raw_inventory := payload.get("inventory"): 1369 if "data" in raw_inventory: 1370 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1371 1372 activities: activity.CharacterActivity | None = None 1373 if raw_activities := payload.get("activities"): 1374 activities = self.deserialize_character_activity(raw_activities["data"]) 1375 1376 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1377 if raw_equipments := payload.get("equipment"): 1378 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1379 1380 progressions_: character.CharacterProgression | None = None 1381 if raw_progressions := payload.get("progressions"): 1382 progressions_ = self.deserialize_character_progressions( 1383 raw_progressions["data"] 1384 ) 1385 1386 render_data: character.RenderedData | None = None 1387 if raw_render_data := payload.get("renderData"): 1388 render_data = self.deserialize_character_render_data( 1389 raw_render_data["data"] 1390 ) 1391 1392 character_records: typing.Optional[ 1393 collections.Mapping[int, records.CharacterRecord] 1394 ] = None 1395 if raw_char_records := payload.get("records"): 1396 character_records = self.deserialize_characters_records( 1397 raw_char_records["data"] 1398 ) 1399 1400 item_components: components.ItemsComponent | None = None 1401 if raw_item_components := payload.get("itemComponents"): 1402 item_components = self.deserialize_items_component(raw_item_components) 1403 1404 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1405 if raw_nodes := payload.get("presentationNodes"): 1406 nodes = { 1407 int(node_hash): self._deserialize_node(node) 1408 for node_hash, node in raw_nodes["data"]["nodes"].items() 1409 } 1410 1411 collectibles: items.Collectible | None = None 1412 if raw_collectibles := payload.get("collectibles"): 1413 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1414 1415 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1416 if raw_currencies := payload.get("currencyLookups"): 1417 if "data" in raw_currencies: 1418 currency_lookups = self._deserialize_currencies(raw_currencies) 1419 1420 return components.CharacterComponent( 1421 activities=activities, 1422 equipment=equipment, 1423 inventory=inventory, 1424 progressions=progressions_, 1425 render_data=render_data, 1426 character=character_, 1427 character_records=character_records, 1428 profile_records=None, 1429 item_components=item_components, 1430 currency_lookups=currency_lookups, 1431 collectibles=collectibles, 1432 nodes=nodes, 1433 ) 1434 1435 def _set_entity_attrs( 1436 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1437 ) -> entity.Entity: 1438 properties = payload[key] 1439 name = typedefs.unknown(properties["name"]) 1440 description = typedefs.unknown(properties["description"]) 1441 1442 return entity.Entity( 1443 net=self._net, 1444 hash=payload["hash"], 1445 index=payload["index"], 1446 name=name, 1447 description=description, 1448 has_icon=properties["hasIcon"], 1449 icon=assets.Image.default_or_else(properties.get("icon")), 1450 ) 1451 1452 def deserialize_inventory_results( 1453 self, payload: typedefs.JSONObject 1454 ) -> iterators.Iterator[entity.SearchableEntity]: 1455 return iterators.Iterator( 1456 [ 1457 entity.SearchableEntity( 1458 net=self._net, 1459 hash=data["hash"], 1460 entity_type=data["entityType"], 1461 weight=data["weight"], 1462 suggested_words=payload["suggestedWords"], 1463 name=data["displayProperties"]["name"], 1464 has_icon=data["displayProperties"]["hasIcon"], 1465 description=typedefs.unknown( 1466 data["displayProperties"]["description"] 1467 ), 1468 icon=assets.Image(data["displayProperties"]["icon"]), 1469 ) 1470 for data in payload["results"]["results"] 1471 ] 1472 ) 1473 1474 def _deserialize_inventory_item_objects( 1475 self, payload: typedefs.JSONObject 1476 ) -> entity.InventoryEntityObjects: 1477 return entity.InventoryEntityObjects( 1478 action=payload.get("action"), 1479 set_data=payload.get("setData"), 1480 stats=payload.get("stats"), 1481 equipping_block=payload.get("equippingBlock"), 1482 translation_block=payload.get("translationBlock"), 1483 preview=payload.get("preview"), 1484 quality=payload.get("quality"), 1485 value=payload.get("value"), 1486 source_data=payload.get("sourceData"), 1487 objectives=payload.get("objectives"), 1488 plug=payload.get("plug"), 1489 metrics=payload.get("metrics"), 1490 gearset=payload.get("gearset"), 1491 sack=payload.get("sack"), 1492 sockets=payload.get("sockets"), 1493 summary=payload.get("summary"), 1494 talent_gird=payload.get("talentGrid"), 1495 investments_stats=payload.get("investmentStats"), 1496 perks=payload.get("perks"), 1497 animations=payload.get("animations", []), 1498 links=payload.get("links", []), 1499 ) 1500 1501 def deserialize_inventory_entity( # noqa: C901 Too complex. 1502 self, payload: typedefs.JSONObject, / 1503 ) -> entity.InventoryEntity: 1504 props = self._set_entity_attrs(payload) 1505 objects = self._deserialize_inventory_item_objects(payload) 1506 1507 collectible_hash: int | None = None 1508 if raw_collectible_hash := payload.get("collectibleHash"): 1509 collectible_hash = int(raw_collectible_hash) 1510 1511 secondary_icon: assets.Image | None = None 1512 if raw_second_icon := payload.get("secondaryIcon"): 1513 secondary_icon = assets.Image(raw_second_icon) 1514 1515 secondary_overlay: assets.Image | None = None 1516 if raw_second_overlay := payload.get("secondaryOverlay"): 1517 secondary_overlay = assets.Image(raw_second_overlay) 1518 1519 secondary_special: assets.Image | None = None 1520 if raw_second_special := payload.get("secondarySpecial"): 1521 secondary_special = assets.Image(raw_second_special) 1522 1523 screenshot: assets.Image | None = None 1524 if raw_screenshot := payload.get("screenshot"): 1525 screenshot = assets.Image(raw_screenshot) 1526 1527 watermark_icon: assets.Image | None = None 1528 if raw_watermark_icon := payload.get("iconWatermark"): 1529 watermark_icon = assets.Image(raw_watermark_icon) 1530 1531 watermark_shelved: assets.Image | None = None 1532 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1533 watermark_shelved = assets.Image(raw_watermark_shelved) 1534 1535 about: str | None = None 1536 if raw_about := payload.get("flavorText"): 1537 about = raw_about 1538 1539 ui_item_style: str | None = None 1540 if raw_ui_style := payload.get("uiItemDisplayStyle"): 1541 ui_item_style = raw_ui_style 1542 1543 tier_and_name: str | None = None 1544 if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"): 1545 tier_and_name = raw_tier_and_name 1546 1547 type_name: str | None = None 1548 if raw_type_name := payload.get("itemTypeDisplayName"): 1549 type_name = raw_type_name 1550 1551 display_source: str | None = None 1552 if raw_display_source := payload.get("displaySource"): 1553 display_source = raw_display_source 1554 1555 lorehash: int | None = None 1556 if raw_lore_hash := payload.get("loreHash"): 1557 lorehash = int(raw_lore_hash) 1558 1559 summary_hash: int | None = None 1560 if raw_summary_hash := payload.get("summaryItemHash"): 1561 summary_hash = raw_summary_hash 1562 1563 breaker_type_hash: int | None = None 1564 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1565 breaker_type_hash = int(raw_breaker_type_hash) 1566 1567 damage_types: typing.Optional[collections.Sequence[int]] = None 1568 if raw_damage_types := payload.get("damageTypes"): 1569 damage_types = [int(type_) for type_ in raw_damage_types] 1570 1571 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1572 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1573 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1574 1575 default_damagetype_hash: int | None = None 1576 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1577 default_damagetype_hash = int(raw_defaultdmg_hash) 1578 1579 emblem_objective_hash: int | None = None 1580 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1581 emblem_objective_hash = int(raw_emblem_obj_hash) 1582 1583 tier_type: enums.TierType | None = None 1584 tier: enums.ItemTier | None = None 1585 bucket_hash: int | None = None 1586 recovery_hash: int | None = None 1587 tier_name: str | None = None 1588 isinstance_item: bool = False 1589 expire_tool_tip: str | None = None 1590 expire_in_orbit_message: str | None = None 1591 suppress_expiration: bool = False 1592 max_stack_size: int | None = None 1593 stack_label: str | None = None 1594 1595 if inventory := payload.get("inventory"): 1596 tier_type = enums.TierType(int(inventory["tierType"])) 1597 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1598 bucket_hash = int(inventory["bucketTypeHash"]) 1599 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1600 tier_name = inventory["tierTypeName"] 1601 isinstance_item = inventory["isInstanceItem"] 1602 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1603 max_stack_size = int(inventory["maxStackSize"]) 1604 1605 try: 1606 stack_label = inventory["stackUniqueLabel"] 1607 except KeyError: 1608 pass 1609 1610 return entity.InventoryEntity( 1611 net=self._net, 1612 collectible_hash=collectible_hash, 1613 name=props.name, 1614 about=about, 1615 emblem_objective_hash=emblem_objective_hash, 1616 suppress_expiration=suppress_expiration, 1617 max_stack_size=max_stack_size, 1618 stack_label=stack_label, 1619 tier=tier, 1620 tier_type=tier_type, 1621 tier_name=tier_name, 1622 bucket_hash=bucket_hash, 1623 recovery_bucket_hash=recovery_hash, 1624 isinstance_item=isinstance_item, 1625 expire_in_orbit_message=expire_in_orbit_message, 1626 expiration_tooltip=expire_tool_tip, 1627 lore_hash=lorehash, 1628 type_and_tier_name=tier_and_name, 1629 summary_hash=summary_hash, 1630 ui_display_style=ui_item_style, 1631 type_name=type_name, 1632 breaker_type_hash=breaker_type_hash, 1633 description=props.description, 1634 display_source=display_source, 1635 hash=props.hash, 1636 damage_types=damage_types, 1637 index=props.index, 1638 icon=props.icon, 1639 has_icon=props.has_icon, 1640 screenshot=screenshot, 1641 watermark_icon=watermark_icon, 1642 watermark_shelved=watermark_shelved, 1643 secondary_icon=secondary_icon, 1644 secondary_overlay=secondary_overlay, 1645 secondary_special=secondary_special, 1646 type=enums.ItemType(int(payload["itemType"])), 1647 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1648 trait_ids=[trait for trait in payload.get("traitIds", [])], 1649 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1650 item_class=enums.Class(int(payload["classType"])), 1651 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1652 breaker_type=int(payload["breakerType"]), 1653 default_damagetype=int(payload["defaultDamageType"]), 1654 default_damagetype_hash=default_damagetype_hash, 1655 damagetype_hashes=damagetype_hashes, 1656 tooltip_notifications=payload["tooltipNotifications"], 1657 not_transferable=payload["nonTransferrable"], 1658 allow_actions=payload["allowActions"], 1659 is_equippable=payload["equippable"], 1660 objects=objects, 1661 background_colors=payload.get("backgroundColor", {}), 1662 season_hash=payload.get("seasonHash"), 1663 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1664 ) 1665 1666 def deserialize_objective_entity( 1667 self, payload: typedefs.JSONObject, / 1668 ) -> entity.ObjectiveEntity: 1669 props = self._set_entity_attrs(payload) 1670 return entity.ObjectiveEntity( 1671 net=self._net, 1672 hash=props.hash, 1673 index=props.index, 1674 description=props.description, 1675 name=props.name, 1676 has_icon=props.has_icon, 1677 icon=props.icon, 1678 unlock_value_hash=payload["unlockValueHash"], 1679 completion_value=payload["completionValue"], 1680 scope=entity.GatingScope(int(payload["scope"])), 1681 location_hash=payload["locationHash"], 1682 allowed_negative_value=payload["allowNegativeValue"], 1683 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1684 counting_downward=payload["isCountingDownward"], 1685 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1686 progress_description=payload["progressDescription"], 1687 perks=payload["perks"], 1688 stats=payload["stats"], 1689 minimum_visibility=payload["minimumVisibilityThreshold"], 1690 allow_over_completion=payload["allowOvercompletion"], 1691 show_value_style=payload["showValueOnComplete"], 1692 display_only_objective=payload["isDisplayOnlyObjective"], 1693 complete_value_style=entity.ValueUIStyle( 1694 int(payload["completedValueStyle"]) 1695 ), 1696 progress_value_style=entity.ValueUIStyle( 1697 int(payload["inProgressValueStyle"]) 1698 ), 1699 ui_label=payload["uiLabel"], 1700 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1701 ) 1702 1703 def _deserialize_activity_values( 1704 self, payload: typedefs.JSONObject, / 1705 ) -> activity.ActivityValues: 1706 team: int | None = None 1707 if raw_team := payload.get("team"): 1708 team = raw_team["basic"]["value"] 1709 return activity.ActivityValues( 1710 assists=payload["assists"]["basic"]["value"], 1711 deaths=payload["deaths"]["basic"]["value"], 1712 kills=payload["kills"]["basic"]["value"], 1713 is_completed=bool(payload["completed"]["basic"]["value"]), 1714 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1715 efficiency=payload["efficiency"]["basic"]["value"], 1716 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1717 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1718 score=payload["score"]["basic"]["value"], 1719 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1720 team=team, 1721 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1722 fireteam_id=payload["fireteamId"]["basic"]["value"], 1723 start_seconds=payload["startSeconds"]["basic"]["value"], 1724 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1725 player_count=payload["playerCount"]["basic"]["value"], 1726 team_score=payload["teamScore"]["basic"]["value"], 1727 ) 1728 1729 def deserialize_activity( 1730 self, 1731 payload: typedefs.JSONObject, 1732 /, 1733 ) -> activity.Activity: 1734 period = time.clean_date(payload["period"]) 1735 details = payload["activityDetails"] 1736 ref_id = int(details["referenceId"]) 1737 instance_id = int(details["instanceId"]) 1738 mode = enums.GameMode(details["mode"]) 1739 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1740 is_private = details["isPrivate"] 1741 membership_type = enums.MembershipType(int(details["membershipType"])) 1742 1743 # Since we're using the same fields for post activity method 1744 # this check is required since post activity doesn't values values 1745 values = self._deserialize_activity_values(payload["values"]) 1746 1747 return activity.Activity( 1748 net=self._net, 1749 hash=ref_id, 1750 instance_id=instance_id, 1751 mode=mode, 1752 modes=modes, 1753 is_private=is_private, 1754 membership_type=membership_type, 1755 occurred_at=period, 1756 values=values, 1757 ) 1758 1759 def deserialize_activities( 1760 self, payload: typedefs.JSONObject 1761 ) -> iterators.Iterator[activity.Activity]: 1762 return iterators.Iterator( 1763 [ 1764 self.deserialize_activity(activity_) 1765 for activity_ in payload["activities"] 1766 ] 1767 ) 1768 1769 def deserialize_extended_weapon_values( 1770 self, payload: typedefs.JSONObject 1771 ) -> activity.ExtendedWeaponValues: 1772 assists: int | None = None 1773 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1774 assists = raw_assists["basic"]["value"] 1775 assists_damage: int | None = None 1776 1777 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1778 assists_damage = raw_assists_damage["basic"]["value"] 1779 1780 return activity.ExtendedWeaponValues( 1781 reference_id=int(payload["referenceId"]), 1782 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1783 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1784 "value" 1785 ], 1786 assists=assists, 1787 assists_damage=assists_damage, 1788 precision_kills_percentage=( 1789 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1790 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1791 "displayValue" 1792 ], 1793 ), 1794 ) 1795 1796 def _deserialize_extended_values( 1797 self, payload: typedefs.JSONObject 1798 ) -> activity.ExtendedValues: 1799 if raw_weapons := payload.get("weapons"): 1800 weapons = [ 1801 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1802 ] 1803 else: 1804 weapons = [] 1805 1806 return activity.ExtendedValues( 1807 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1808 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1809 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1810 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1811 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1812 weapons=weapons, 1813 ) 1814 1815 def deserialize_post_activity_player( 1816 self, payload: typedefs.JSONObject, / 1817 ) -> activity.PostActivityPlayer: 1818 player = payload["player"] 1819 1820 class_hash: int | None = None 1821 if (class_hash := player.get("classHash")) is not None: 1822 class_hash = class_hash 1823 1824 race_hash: int | None = None 1825 if (race_hash := player.get("raceHash")) is not None: 1826 race_hash = race_hash 1827 1828 gender_hash: int | None = None 1829 if (gender_hash := player.get("genderHash")) is not None: 1830 gender_hash = gender_hash 1831 1832 character_class: str | None = None 1833 if character_class := player.get("characterClass"): 1834 character_class = character_class 1835 1836 character_level: int | None = None 1837 if (character_level := player.get("characterLevel")) is not None: 1838 character_level = character_level 1839 1840 return activity.PostActivityPlayer( 1841 standing=int(payload["standing"]), 1842 score=int(payload["score"]["basic"]["value"]), 1843 character_id=payload["characterId"], 1844 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1845 character_class=character_class, 1846 character_level=character_level, 1847 race_hash=race_hash, 1848 gender_hash=gender_hash, 1849 class_hash=class_hash, 1850 light_level=int(player["lightLevel"]), 1851 emblem_hash=int(player["emblemHash"]), 1852 values=self._deserialize_activity_values(payload["values"]), 1853 extended_values=self._deserialize_extended_values(payload["extended"]), 1854 ) 1855 1856 def _deserialize_post_activity_team( 1857 self, payload: typedefs.JSONObject 1858 ) -> activity.PostActivityTeam: 1859 return activity.PostActivityTeam( 1860 id=payload["teamId"], 1861 is_defeated=bool(payload["standing"]["basic"]["value"]), 1862 score=int(payload["score"]["basic"]["value"]), 1863 name=payload["teamName"], 1864 ) 1865 1866 def deserialize_post_activity( 1867 self, payload: typedefs.JSONObject 1868 ) -> activity.PostActivity: 1869 period = time.clean_date(payload["period"]) 1870 details = payload["activityDetails"] 1871 ref_id = int(details["referenceId"]) 1872 instance_id = int(details["instanceId"]) 1873 mode = enums.GameMode(details["mode"]) 1874 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1875 is_private = details["isPrivate"] 1876 membership_type = enums.MembershipType(int(details["membershipType"])) 1877 return activity.PostActivity( 1878 net=self._net, 1879 hash=ref_id, 1880 membership_type=membership_type, 1881 instance_id=instance_id, 1882 mode=mode, 1883 modes=modes, 1884 is_private=is_private, 1885 occurred_at=period, 1886 starting_phase=int(payload["startingPhaseIndex"]), 1887 players=[ 1888 self.deserialize_post_activity_player(player) 1889 for player in payload["entries"] 1890 ], 1891 teams=[ 1892 self._deserialize_post_activity_team(team) for team in payload["teams"] 1893 ], 1894 ) 1895 1896 def _deserialize_aggregated_activity_values( 1897 self, payload: typedefs.JSONObject 1898 ) -> activity.AggregatedActivityValues: 1899 # This ID is always the same for all aggregated values. 1900 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1901 1902 return activity.AggregatedActivityValues( 1903 id=activity_id, 1904 fastest_completion_time=( 1905 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1906 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1907 ), 1908 completions=int(payload["activityCompletions"]["basic"]["value"]), 1909 kills=int(payload["activityKills"]["basic"]["value"]), 1910 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1911 assists=int(payload["activityAssists"]["basic"]["value"]), 1912 seconds_played=( 1913 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1914 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1915 ), 1916 wins=int(payload["activityWins"]["basic"]["value"]), 1917 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1918 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1919 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1920 best_single_score=int( 1921 payload["activityBestSingleGameScore"]["basic"]["value"] 1922 ), 1923 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1924 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1925 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1926 kd_ratio=float( 1927 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1928 ), 1929 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1930 ) 1931 1932 def deserialize_aggregated_activity( 1933 self, payload: typedefs.JSONObject 1934 ) -> activity.AggregatedActivity: 1935 return activity.AggregatedActivity( 1936 hash=int(payload["activityHash"]), 1937 values=self._deserialize_aggregated_activity_values(payload["values"]), 1938 ) 1939 1940 def deserialize_aggregated_activities( 1941 self, payload: typedefs.JSONObject 1942 ) -> iterators.Iterator[activity.AggregatedActivity]: 1943 return iterators.Iterator( 1944 [ 1945 self.deserialize_aggregated_activity(activity) 1946 for activity in payload["activities"] 1947 ] 1948 ) 1949 1950 def deserialize_linked_profiles( 1951 self, payload: typedefs.JSONObject 1952 ) -> profile.LinkedProfile: 1953 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 1954 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1955 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1956 1957 if raw_profile := payload.get("profiles"): 1958 for pfile in raw_profile: 1959 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 1960 1961 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 1962 for raw_error_pfile in raw_profiles_with_errors: 1963 if error_pfile := raw_error_pfile.get("infoCard"): 1964 error_profiles_vec.append( 1965 self.deserialize_destiny_membership(error_pfile) 1966 ) 1967 1968 return profile.LinkedProfile( 1969 bungie_user=bungie_user, 1970 profiles=profiles_vec, 1971 profiles_with_errors=error_profiles_vec, 1972 ) 1973 1974 def deserialize_clan_banners( 1975 self, payload: typedefs.JSONObject 1976 ) -> collections.Sequence[clans.ClanBanner]: 1977 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 1978 if banners := payload.get("clanBannerDecals"): 1979 for k, v in banners.items(): 1980 banner_obj = clans.ClanBanner( 1981 id=int(k), 1982 foreground=assets.Image(v["foregroundPath"]), 1983 background=assets.Image(v["backgroundPath"]), 1984 ) 1985 banners_seq.append(banner_obj) 1986 return banners_seq 1987 1988 def deserialize_public_milestone_content( 1989 self, payload: typedefs.JSONObject 1990 ) -> milestones.MilestoneContent: 1991 items_categories: milestones.MilestoneItems | None = None 1992 1993 if raw_categories := payload.get("itemCategories"): 1994 for item in raw_categories: 1995 title: str | None = None 1996 if raw_title := item.get("title"): 1997 title = raw_title 1998 if raw_hashes := item.get("itemHashes"): 1999 hashes = raw_hashes 2000 2001 items_categories = milestones.MilestoneItems(title=title, hashes=hashes) 2002 2003 tips: typing.MutableSequence[str] = [] 2004 if raw_tips := payload.get("tips"): 2005 tips = raw_tips 2006 2007 return milestones.MilestoneContent( 2008 about=typedefs.unknown(payload["about"]), 2009 status=typedefs.unknown(payload["status"]), 2010 tips=tips, 2011 items=items_categories, 2012 ) 2013 2014 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2015 bungie_user: user.BungieUser | None = None 2016 2017 if raw_bungie_user := payload.get("bungieNetUser"): 2018 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2019 2020 return friends.Friend( 2021 net=self._net, 2022 id=int(payload["lastSeenAsMembershipId"]), 2023 name=typedefs.unknown(payload["bungieGlobalDisplayName"]), 2024 code=payload.get("bungieGlobalDisplayNameCode"), 2025 relationship=enums.Relationship(payload["relationship"]), 2026 user=bungie_user, 2027 online_status=enums.Presence(payload["onlineStatus"]), 2028 online_title=payload["onlineTitle"], 2029 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2030 ) 2031 2032 def deserialize_friends( 2033 self, payload: typedefs.JSONObject 2034 ) -> collections.Sequence[friends.Friend]: 2035 mut_seq: typing.MutableSequence[friends.Friend] = [] 2036 if raw_friends := payload.get("friends"): 2037 for friend in raw_friends: 2038 mut_seq.append(self.deserialize_friend(friend)) 2039 return mut_seq 2040 2041 def deserialize_friend_requests( 2042 self, payload: typedefs.JSONObject 2043 ) -> friends.FriendRequestView: 2044 incoming: typing.MutableSequence[friends.Friend] = [] 2045 outgoing: typing.MutableSequence[friends.Friend] = [] 2046 2047 if raw_incoming_requests := payload.get("incomingRequests"): 2048 for incoming_request in raw_incoming_requests: 2049 incoming.append(self.deserialize_friend(incoming_request)) 2050 2051 if raw_outgoing_requests := payload.get("outgoingRequests"): 2052 for outgoing_request in raw_outgoing_requests: 2053 outgoing.append(self.deserialize_friend(outgoing_request)) 2054 2055 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2056 2057 def _set_fireteam_fields( 2058 self, payload: typedefs.JSONObject, total_results: int | None = None 2059 ) -> fireteams.Fireteam: 2060 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2061 return fireteams.Fireteam( 2062 id=int(payload["fireteamId"]), 2063 group_id=int(payload["groupId"]), 2064 platform=fireteams.FireteamPlatform(payload["platform"]), 2065 is_immediate=payload["isImmediate"], 2066 activity_type=activity_type, 2067 owner_id=int(payload["ownerMembershipId"]), 2068 player_slot_count=payload["playerSlotCount"], 2069 available_player_slots=payload["availablePlayerSlotCount"], 2070 available_alternate_slots=payload["availableAlternateSlotCount"], 2071 title=payload["title"], 2072 date_created=time.clean_date(payload["dateCreated"]), 2073 is_public=payload["isPublic"], 2074 locale=fireteams.FireteamLanguage(payload["locale"]), 2075 is_valid=payload["isValid"], 2076 last_modified=time.clean_date(payload["datePlayerModified"]), 2077 date_modified=time.clean_date(payload["dateModified"]) 2078 if "dateModified" in payload 2079 else None, 2080 scheduled_time=time.clean_date(payload["scheduledTime"]) 2081 if "scheduledTime" in payload 2082 else None, 2083 total_results=total_results or 0, 2084 ) 2085 2086 def deserialize_fireteams( 2087 self, payload: typedefs.JSONObject 2088 ) -> collections.Sequence[fireteams.Fireteam]: 2089 if "results" in payload: 2090 fireteams_ = [ 2091 self._set_fireteam_fields( 2092 elem, total_results=int(payload["totalResults"]) 2093 ) 2094 for elem in payload["results"] 2095 ] 2096 else: 2097 fireteams_ = [] 2098 return fireteams_ 2099 2100 def deserialize_fireteam_destiny_users( 2101 self, payload: typedefs.JSONObject 2102 ) -> fireteams.FireteamUser: 2103 destiny_obj = self.deserialize_destiny_membership(payload) 2104 return fireteams.FireteamUser( 2105 net=self._net, 2106 id=destiny_obj.id, 2107 code=destiny_obj.code, 2108 icon=destiny_obj.icon, 2109 types=destiny_obj.types, 2110 type=destiny_obj.type, 2111 is_public=destiny_obj.is_public, 2112 crossave_override=destiny_obj.crossave_override, 2113 name=destiny_obj.name, 2114 last_seen_name=destiny_obj.last_seen_name, 2115 fireteam_display_name=payload["FireteamDisplayName"], 2116 fireteam_membership_id=enums.MembershipType( 2117 payload["FireteamMembershipType"] 2118 ), 2119 ) 2120 2121 def deserialize_fireteam_members( 2122 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2123 ) -> collections.Sequence[fireteams.FireteamMember]: 2124 members_: list[fireteams.FireteamMember] = [] 2125 if members := payload.get("Members" if not alternatives else "Alternates"): 2126 for member in members: 2127 bungie_fields = self.deserialize_partial_bungie_user(member) 2128 members_fields = fireteams.FireteamMember( 2129 destiny_user=self.deserialize_fireteam_destiny_users(member), 2130 has_microphone=member["hasMicrophone"], 2131 character_id=int(member["characterId"]), 2132 date_joined=time.clean_date(member["dateJoined"]), 2133 last_platform_invite_date=time.clean_date( 2134 member["lastPlatformInviteAttemptDate"] 2135 ), 2136 last_platform_invite_result=int( 2137 member["lastPlatformInviteAttemptResult"] 2138 ), 2139 net=self._net, 2140 name=bungie_fields.name, 2141 id=bungie_fields.id, 2142 icon=bungie_fields.icon, 2143 is_public=bungie_fields.is_public, 2144 crossave_override=bungie_fields.crossave_override, 2145 types=bungie_fields.types, 2146 type=bungie_fields.type, 2147 ) 2148 members_.append(members_fields) 2149 return members_ 2150 2151 def deserialize_available_fireteam( 2152 self, payload: typedefs.JSONObject 2153 ) -> fireteams.AvailableFireteam: 2154 fields = self._set_fireteam_fields(payload["Summary"]) 2155 return fireteams.AvailableFireteam( 2156 id=fields.id, 2157 group_id=fields.group_id, 2158 platform=fields.platform, 2159 activity_type=fields.activity_type, 2160 is_immediate=fields.is_immediate, 2161 is_public=fields.is_public, 2162 is_valid=fields.is_valid, 2163 owner_id=fields.owner_id, 2164 player_slot_count=fields.player_slot_count, 2165 available_player_slots=fields.available_player_slots, 2166 available_alternate_slots=fields.available_alternate_slots, 2167 title=fields.title, 2168 date_created=fields.date_created, 2169 locale=fields.locale, 2170 last_modified=fields.last_modified, 2171 total_results=fields.total_results, 2172 scheduled_time=fields.scheduled_time, 2173 date_modified=fields.date_modified, 2174 members=self.deserialize_fireteam_members(payload), 2175 alternatives=self.deserialize_fireteam_members(payload, alternatives=True), 2176 ) 2177 2178 def deserialize_available_fireteams( 2179 self, data: typedefs.JSONObject 2180 ) -> collections.Sequence[fireteams.AvailableFireteam]: 2181 if raw_results := data.get("results"): 2182 fireteam_results: list[fireteams.AvailableFireteam] = [ 2183 self.deserialize_available_fireteam(f) for f in raw_results 2184 ] 2185 else: 2186 fireteam_results = [] 2187 return fireteam_results 2188 2189 def deserialize_fireteam_party( 2190 self, payload: typedefs.JSONObject 2191 ) -> fireteams.FireteamParty: 2192 last_destination_hash: int | None = None 2193 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2194 last_destination_hash = int(raw_dest_hash) 2195 2196 return fireteams.FireteamParty( 2197 members=[ 2198 self._deserialize_fireteam_party_member(member) 2199 for member in payload["partyMembers"] 2200 ], 2201 activity=self._deserialize_fireteam_party_current_activity( 2202 payload["currentActivity"] 2203 ), 2204 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2205 last_destination_hash=last_destination_hash, 2206 tracking=payload["tracking"], 2207 ) 2208 2209 def _deserialize_fireteam_party_member( 2210 self, payload: typedefs.JSONObject 2211 ) -> fireteams.FireteamPartyMember: 2212 status = fireteams.FireteamPartyMemberState(payload["status"]) 2213 2214 return fireteams.FireteamPartyMember( 2215 membership_id=int(payload["membershipId"]), 2216 emblem_hash=int(payload["emblemHash"]), 2217 status=status, 2218 display_name=payload["displayName"] if payload["displayName"] else None, 2219 ) 2220 2221 def _deserialize_fireteam_party_current_activity( 2222 self, payload: typedefs.JSONObject 2223 ) -> fireteams.FireteamPartyCurrentActivity: 2224 start_date: datetime.datetime | None = None 2225 if raw_start_date := payload.get("startTime"): 2226 start_date = time.clean_date(raw_start_date) 2227 2228 end_date: datetime.datetime | None = None 2229 if raw_end_date := payload.get("endTime"): 2230 end_date = time.clean_date(raw_end_date) 2231 return fireteams.FireteamPartyCurrentActivity( 2232 start_time=start_date, 2233 end_time=end_date, 2234 score=float(payload["score"]), 2235 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2236 opponents_count=int(payload["numberOfOpponents"]), 2237 player_count=int(payload["numberOfPlayers"]), 2238 ) 2239 2240 def _deserialize_fireteam_party_settings( 2241 self, payload: typedefs.JSONObject 2242 ) -> fireteams.FireteamPartySettings: 2243 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2244 return fireteams.FireteamPartySettings( 2245 open_slots=int(payload["openSlots"]), 2246 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2247 closed_reasons=closed_reasons, 2248 ) 2249 2250 def deserialize_seasonal_artifact( 2251 self, payload: typedefs.JSONObject 2252 ) -> season.Artifact: 2253 if raw_artifact := payload.get("seasonalArtifact"): 2254 if points := raw_artifact.get("pointProgression"): 2255 points_prog = progressions.Progression( 2256 hash=points["progressionHash"], 2257 level=points["level"], 2258 cap=points["levelCap"], 2259 daily_limit=points["dailyLimit"], 2260 weekly_limit=points["weeklyLimit"], 2261 current_progress=points["currentProgress"], 2262 daily_progress=points["dailyProgress"], 2263 needed=points["progressToNextLevel"], 2264 next_level=points["nextLevelAt"], 2265 ) 2266 2267 if bonus := raw_artifact.get("powerBonusProgression"): 2268 power_bonus_prog = progressions.Progression( 2269 hash=bonus["progressionHash"], 2270 level=bonus["level"], 2271 cap=bonus["levelCap"], 2272 daily_limit=bonus["dailyLimit"], 2273 weekly_limit=bonus["weeklyLimit"], 2274 current_progress=bonus["currentProgress"], 2275 daily_progress=bonus["dailyProgress"], 2276 needed=bonus["progressToNextLevel"], 2277 next_level=bonus["nextLevelAt"], 2278 ) 2279 artifact = season.Artifact( 2280 hash=raw_artifact["artifactHash"], 2281 power_bonus=raw_artifact["powerBonus"], 2282 acquired_points=raw_artifact["pointsAcquired"], 2283 bonus=power_bonus_prog, 2284 points=points_prog, 2285 ) 2286 return artifact 2287 2288 def deserialize_profile_progression( 2289 self, payload: typedefs.JSONObject 2290 ) -> profile.ProfileProgression: 2291 return profile.ProfileProgression( 2292 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2293 checklist={ 2294 int(check_id): checklists 2295 for check_id, checklists in payload["data"]["checklists"].items() 2296 }, 2297 ) 2298 2299 def deserialize_instanced_item( 2300 self, payload: typedefs.JSONObject 2301 ) -> items.ItemInstance: 2302 damage_type_hash: int | None = None 2303 if raw_damagetype_hash := payload.get("damageTypeHash"): 2304 damage_type_hash = int(raw_damagetype_hash) 2305 2306 required_hashes: typing.Optional[collections.Collection[int]] = None 2307 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2308 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2309 2310 breaker_type: items.ItemBreakerType | None = None 2311 if raw_break_type := payload.get("breakerType"): 2312 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2313 2314 breaker_type_hash: int | None = None 2315 if raw_break_type_hash := payload.get("breakerTypeHash"): 2316 breaker_type_hash = int(raw_break_type_hash) 2317 2318 energy: items.ItemEnergy | None = None 2319 if raw_energy := payload.get("energy"): 2320 energy = self.deserialize_item_energy(raw_energy) 2321 2322 primary_stats = None 2323 if raw_primary_stats := payload.get("primaryStat"): 2324 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2325 2326 return items.ItemInstance( 2327 damage_type=enums.DamageType(int(payload["damageType"])), 2328 damage_type_hash=damage_type_hash, 2329 primary_stat=primary_stats, 2330 item_level=int(payload["itemLevel"]), 2331 quality=int(payload["quality"]), 2332 is_equipped=payload["isEquipped"], 2333 can_equip=payload["canEquip"], 2334 equip_required_level=int(payload["equipRequiredLevel"]), 2335 required_equip_unlock_hashes=required_hashes, 2336 cant_equip_reason=int(payload["cannotEquipReason"]), 2337 breaker_type=breaker_type, 2338 breaker_type_hash=breaker_type_hash, 2339 energy=energy, 2340 ) 2341 2342 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2343 energy_hash: int | None = None 2344 if raw_energy_hash := payload.get("energyTypeHash"): 2345 energy_hash = int(raw_energy_hash) 2346 2347 return items.ItemEnergy( 2348 hash=energy_hash, 2349 type=items.ItemEnergyType(int(payload["energyType"])), 2350 capacity=int(payload["energyCapacity"]), 2351 used_energy=int(payload["energyUsed"]), 2352 unused_energy=int(payload["energyUnused"]), 2353 ) 2354 2355 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2356 perk_hash: int | None = None 2357 if raw_perk_hash := payload.get("perkHash"): 2358 perk_hash = int(raw_perk_hash) 2359 2360 return items.ItemPerk( 2361 hash=perk_hash, 2362 icon=assets.Image(payload["iconPath"]), 2363 is_active=payload["isActive"], 2364 is_visible=payload["visible"], 2365 ) 2366 2367 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2368 plug_hash: int | None = None 2369 if raw_plug_hash := payload.get("plugHash"): 2370 plug_hash = int(raw_plug_hash) 2371 2372 enable_fail_indexes: list[int] | None = None 2373 if raw_indexes := payload.get("enableFailIndexes"): 2374 enable_fail_indexes = [int(index) for index in raw_indexes] 2375 2376 return items.ItemSocket( 2377 plug_hash=plug_hash, 2378 is_enabled=payload["isEnabled"], 2379 enable_fail_indexes=enable_fail_indexes, 2380 is_visible=payload.get("visible"), 2381 ) 2382 2383 def deserialize_item_stats_view( 2384 self, payload: typedefs.JSONObject 2385 ) -> items.ItemStatsView: 2386 return items.ItemStatsView( 2387 stat_hash=payload.get("statHash"), value=payload.get("value") 2388 ) 2389 2390 def deserialize_plug_item_state( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.PlugItemState: 2393 item_hash: int | None = None 2394 if raw_item_hash := payload.get("plugItemHash"): 2395 item_hash = int(raw_item_hash) 2396 2397 insert_fail_indexes: list[int] | None = None 2398 if raw_fail_indexes := payload.get("insertFailIndexes"): 2399 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2400 2401 enable_fail_indexes: list[int] | None = None 2402 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2403 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2404 2405 return items.PlugItemState( 2406 item_hash=item_hash, 2407 insert_fail_indexes=insert_fail_indexes, 2408 enable_fail_indexes=enable_fail_indexes, 2409 is_enabled=payload["enabled"], 2410 can_insert=payload["canInsert"], 2411 )
The base deserialization factory class for all aiobungie objects.
This entity factory is used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
72 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 73 return user.BungieUser( 74 id=int(data["membershipId"]), 75 created_at=time.clean_date(data["firstAccess"]), 76 name=data.get("cachedBungieGlobalDisplayName"), 77 is_deleted=data["isDeleted"], 78 about=data["about"], 79 updated_at=time.clean_date(data["lastUpdate"]), 80 psn_name=data.get("psnDisplayName", None), 81 stadia_name=data.get("stadiaDisplayName", None), 82 steam_name=data.get("steamDisplayName", None), 83 twitch_name=data.get("twitchDisplayName", None), 84 blizzard_name=data.get("blizzardDisplayName", None), 85 status=data["statusText"], 86 locale=data["locale"], 87 picture=assets.Image(path=str(data["profilePicturePath"])), 88 code=data.get("cachedBungieGlobalDisplayNameCode", None), 89 unique_name=data.get("uniqueName", None), 90 theme_id=int(data["profileTheme"]), 91 show_activity=bool(data["showActivity"]), 92 theme_name=data["profileThemeName"], 93 display_title=data["userTitleDisplay"], 94 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
96 def deserialize_partial_bungie_user( 97 self, payload: typedefs.JSONObject 98 ) -> user.PartialBungieUser: 99 return user.PartialBungieUser( 100 net=self._net, 101 types=[ 102 enums.MembershipType(type_) 103 for type_ in payload.get("applicableMembershipTypes", []) 104 ], 105 name=payload.get("displayName"), 106 id=int(payload["membershipId"]), 107 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 108 is_public=payload["isPublic"], 109 icon=assets.Image(payload.get("iconPath", "")), 110 type=enums.MembershipType(payload["membershipType"]), 111 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
113 def deserialize_destiny_membership( 114 self, payload: typedefs.JSONObject 115 ) -> user.DestinyMembership: 116 name: str | None = None 117 if (raw_name := payload.get("bungieGlobalDisplayName")) is not None: 118 name = typedefs.unknown(raw_name) 119 120 return user.DestinyMembership( 121 net=self._net, 122 id=int(payload["membershipId"]), 123 name=name, 124 code=payload.get("bungieGlobalDisplayNameCode", None), 125 last_seen_name=payload.get("LastSeenDisplayName") 126 or payload.get("displayName") # noqa: W503 127 or "", # noqa: W503 128 type=enums.MembershipType(payload["membershipType"]), 129 is_public=payload["isPublic"], 130 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 131 icon=assets.Image(payload.get("iconPath", "")), 132 types=[ 133 enums.MembershipType(type_) 134 for type_ in payload.get("applicableMembershipTypes", []) 135 ], 136 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
138 def deserialize_destiny_memberships( 139 self, data: typedefs.JSONArray 140 ) -> collections.Sequence[user.DestinyMembership]: 141 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
143 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 144 primary_membership_id: int | None = None 145 if raw_primary_id := data.get("primaryMembershipId"): 146 primary_membership_id = int(raw_primary_id) 147 148 return user.User( 149 bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]), 150 memberships=self.deserialize_destiny_memberships( 151 data["destinyMemberships"] 152 ), 153 primary_membership_id=primary_membership_id, 154 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
156 def deserialize_searched_user( 157 self, payload: typedefs.JSONObject 158 ) -> user.SearchableDestinyUser: 159 code: int | None = None 160 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 161 code = int(raw_code) 162 163 bungie_id: int | None = None 164 if raw_bungie_id := payload.get("bungieNetMembershipId"): 165 bungie_id = int(raw_bungie_id) 166 167 return user.SearchableDestinyUser( 168 name=typedefs.unknown(payload["bungieGlobalDisplayName"]), 169 code=code, 170 bungie_id=bungie_id, 171 memberships=self.deserialize_destiny_memberships( 172 payload["destinyMemberships"] 173 ), 174 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
176 def deserialize_user_credentials( 177 self, payload: typedefs.JSONArray 178 ) -> collections.Sequence[user.UserCredentials]: 179 return [ 180 user.UserCredentials( 181 type=enums.CredentialType(int(creds["credentialType"])), 182 display_name=creds["credentialDisplayName"], 183 is_public=creds["isPublic"], 184 self_as_string=creds.get("credentialAsString"), 185 ) 186 for creds in payload 187 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
189 def deserialize_user_themes( 190 self, payload: typedefs.JSONArray 191 ) -> collections.Sequence[user.UserThemes]: 192 return [ 193 user.UserThemes( 194 id=int(entry["userThemeId"]), 195 name=entry["userThemeName"] if "userThemeName" in entry else None, 196 description=entry["userThemeDescription"] 197 if "userThemeDescription" in entry 198 else None, 199 ) 200 for entry in payload 201 ]
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
203 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 204 # This is kinda redundant 205 data = payload 206 207 # This is always outside the details. 208 current_user_map: collections.Mapping[str, clans.ClanMember] = {} 209 if raw_current_user_map := payload.get("currentUserMemberMap"): 210 current_user_map = { 211 membership_type: self.deserialize_clan_member(membership) 212 for membership_type, membership in raw_current_user_map.items() 213 } 214 215 try: 216 data = payload["detail"] 217 except KeyError: 218 pass 219 220 id = data["groupId"] 221 name = data["name"] 222 created_at = data["creationDate"] 223 member_count = data["memberCount"] 224 about = data["about"] 225 motto = data["motto"] 226 is_public = data["isPublic"] 227 banner = assets.Image(str(data["bannerPath"])) 228 avatar = assets.Image(str(data["avatarPath"])) 229 tags = data["tags"] 230 type = data["groupType"] 231 232 features = data["features"] 233 features_obj = clans.ClanFeatures( 234 max_members=features["maximumMembers"], 235 max_membership_types=features["maximumMembershipsOfGroupType"], 236 capabilities=features["capabilities"], 237 membership_types=features["membershipTypes"], 238 invite_permissions=features["invitePermissionOverride"], 239 update_banner_permissions=features["updateBannerPermissionOverride"], 240 update_culture_permissions=features["updateCulturePermissionOverride"], 241 join_level=features["joinLevel"], 242 ) 243 244 information: typedefs.JSONObject = data["clanInfo"] 245 progression: collections.Mapping[int, progressions.Progression] = { 246 int(prog_hash): self.deserialize_progressions(prog) 247 for prog_hash, prog in information["d2ClanProgressions"].items() 248 } 249 250 return clans.Clan( 251 net=self._net, 252 id=int(id), 253 name=name, 254 type=enums.GroupType(type), 255 created_at=time.clean_date(created_at), 256 member_count=member_count, 257 motto=motto, 258 about=about, 259 is_public=is_public, 260 banner=banner, 261 avatar=avatar, 262 tags=tags, 263 features=features_obj, 264 owner=self.deserialize_clan_member(payload["founder"]) 265 if "founder" in payload 266 else None, 267 progressions=progression, 268 call_sign=information["clanCallsign"], 269 banner_data=information["clanBannerData"], 270 chat_security=data["chatSecurity"], 271 conversation_id=int(data["conversationId"]), 272 allow_chat=data["allowChat"], 273 theme=data["theme"], 274 current_user_membership=current_user_map, 275 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
277 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 278 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 279 return clans.ClanMember( 280 net=self._net, 281 last_seen_name=destiny_user.last_seen_name, 282 id=destiny_user.id, 283 name=destiny_user.name, 284 icon=destiny_user.icon, 285 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 286 group_id=int(data["groupId"]), 287 joined_at=time.clean_date(data["joinDate"]), 288 types=destiny_user.types, 289 is_public=destiny_user.is_public, 290 type=destiny_user.type, 291 code=destiny_user.code, 292 is_online=data["isOnline"], 293 crossave_override=destiny_user.crossave_override, 294 bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 295 if "bungieNetUserInfo" in data 296 else None, 297 member_type=enums.ClanMemberType(int(data["memberType"])), 298 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
300 def deserialize_clan_members( 301 self, data: typedefs.JSONObject, / 302 ) -> iterators.Iterator[clans.ClanMember]: 303 return iterators.Iterator( 304 [self.deserialize_clan_member(member) for member in data["results"]] 305 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.Iterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
307 def deserialize_group_member( 308 self, payload: typedefs.JSONObject 309 ) -> clans.GroupMember: 310 member = payload["member"] 311 return clans.GroupMember( 312 net=self._net, 313 join_date=time.clean_date(member["joinDate"]), 314 group_id=int(member["groupId"]), 315 member_type=enums.ClanMemberType(member["memberType"]), 316 is_online=member["isOnline"], 317 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 318 inactive_memberships=payload.get("areAllMembershipsInactive", None), 319 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 320 group=self.deserialize_clan(payload["group"]), 321 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.GroupMember: A group member object.
335 def deserialize_clan_conversations( 336 self, payload: typedefs.JSONArray 337 ) -> collections.Sequence[clans.ClanConversation]: 338 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
340 def deserialize_app_owner( 341 self, payload: typedefs.JSONObject 342 ) -> application.ApplicationOwner: 343 return application.ApplicationOwner( 344 net=self._net, 345 name=payload.get("bungieGlobalDisplayName"), 346 id=int(payload["membershipId"]), 347 type=enums.MembershipType(payload["membershipType"]), 348 icon=assets.Image(str(payload["iconPath"])), 349 is_public=payload["isPublic"], 350 code=payload.get("bungieGlobalDisplayNameCode", None), 351 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
353 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 354 return application.Application( 355 id=int(payload["applicationId"]), 356 name=payload["name"], 357 link=payload["link"], 358 status=payload["status"], 359 redirect_url=payload.get("redirectUrl", None), 360 created_at=time.clean_date(str(payload["creationDate"])), 361 published_at=time.clean_date(str(payload["firstPublished"])), 362 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 363 scope=payload.get("scope"), 364 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
390 def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile: 391 payload = payload["data"] 392 id = int(payload["userInfo"]["membershipId"]) 393 name = payload["userInfo"]["displayName"] 394 is_public = payload["userInfo"]["isPublic"] 395 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 396 last_played = time.clean_date(str(payload["dateLastPlayed"])) 397 character_ids = [int(cid) for cid in payload["characterIds"]] 398 power_cap = payload["currentSeasonRewardPowerCap"] 399 400 return profile.Profile( 401 id=int(id), 402 name=name, 403 is_public=is_public, 404 type=type, 405 last_played=last_played, 406 character_ids=character_ids, 407 power_cap=power_cap, 408 net=self._net, 409 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Profile: A profile object of the deserialized payload.
411 def deserialize_profile_item( 412 self, payload: typedefs.JSONObject 413 ) -> profile.ProfileItemImpl: 414 instance_id: int | None = None 415 if raw_instance_id := payload.get("itemInstanceId"): 416 instance_id = int(raw_instance_id) 417 418 version_number: int | None = None 419 if raw_version := payload.get("versionNumber"): 420 version_number = int(raw_version) 421 422 transfer_status = enums.TransferStatus(payload["transferStatus"]) 423 424 return profile.ProfileItemImpl( 425 net=self._net, 426 hash=payload["itemHash"], 427 quantity=payload["quantity"], 428 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 429 location=enums.ItemLocation(payload["location"]), 430 bucket=payload["bucketHash"], 431 transfer_status=transfer_status, 432 lockable=payload["lockable"], 433 state=enums.ItemState(payload["state"]), 434 dismantle_permissions=payload["dismantlePermission"], 435 is_wrapper=payload["isWrapper"], 436 instance_id=instance_id, 437 version_number=version_number, 438 ornament_id=payload.get("overrideStyleItemHash"), 439 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
441 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 442 return records.Objective( 443 net=self._net, 444 hash=payload["objectiveHash"], 445 visible=payload["visible"], 446 complete=payload["complete"], 447 completion_value=payload["completionValue"], 448 progress=payload.get("progress"), 449 destination_hash=payload.get("destinationHash"), 450 activity_hash=payload.get("activityHash"), 451 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
454 def deserialize_records( 455 self, 456 payload: typedefs.JSONObject, 457 scores: records.RecordScores | None = None, 458 **nodes: int, 459 ) -> records.Record: 460 objectives: list[records.Objective] | None = None 461 interval_objectives: list[records.Objective] | None = None 462 record_state: records.RecordState | int 463 464 record_state = records.RecordState(payload["state"]) 465 466 if raw_objs := payload.get("objectives"): 467 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 468 469 if raw_interval_objs := payload.get("intervalObjectives"): 470 interval_objectives = [ 471 self.deserialize_objectives(obj) for obj in raw_interval_objs 472 ] 473 474 return records.Record( 475 scores=scores, 476 categories_node_hash=nodes.get("categories_hash"), 477 seals_node_hash=nodes.get("seals_hash"), 478 state=record_state, 479 objectives=objectives, 480 interval_objectives=interval_objectives, 481 redeemed_count=payload.get("intervalsRedeemedCount", 0), 482 completion_times=payload.get("completedCount", None), 483 reward_visibility=payload.get("rewardVisibility"), 484 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
records.RecordScores | None): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
486 def deserialize_character_records( 487 self, 488 payload: typedefs.JSONObject, 489 scores: records.RecordScores | None = None, 490 record_hashes: list[int] | None = None, 491 ) -> records.CharacterRecord: 492 record = self.deserialize_records(payload, scores) 493 return records.CharacterRecord( 494 scores=scores, 495 categories_node_hash=record.categories_node_hash, 496 seals_node_hash=record.seals_node_hash, 497 state=record.state, 498 objectives=record.objectives, 499 interval_objectives=record.interval_objectives, 500 redeemed_count=payload.get("intervalsRedeemedCount", 0), 501 completion_times=payload.get("completedCount"), 502 reward_visibility=payload.get("rewardVisibility"), 503 record_hashes=record_hashes or [], 504 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
506 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 507 return character.Dye( 508 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 509 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
511 def deserialize_character_customization( 512 self, payload: typedefs.JSONObject 513 ) -> character.CustomizationOptions: 514 return character.CustomizationOptions( 515 personality=payload["personality"], 516 face=payload["face"], 517 skin_color=payload["skinColor"], 518 lip_color=payload["lipColor"], 519 eye_color=payload["eyeColor"], 520 hair_colors=payload.get("hairColors", []), 521 feature_colors=payload.get("featureColors", []), 522 decal_color=payload["decalColor"], 523 wear_helmet=payload["wearHelmet"], 524 hair_index=payload["hairIndex"], 525 feature_index=payload["featureIndex"], 526 decal_index=payload["decalIndex"], 527 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
529 def deserialize_character_minimal_equipments( 530 self, payload: typedefs.JSONObject 531 ) -> character.MinimalEquipments: 532 if raw_dyes := payload.get("dyes"): 533 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 534 else: 535 dyes = [] 536 537 return character.MinimalEquipments( 538 net=self._net, item_hash=payload["itemHash"], dyes=dyes 539 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
541 def deserialize_character_render_data( 542 self, payload: typedefs.JSONObject, / 543 ) -> character.RenderedData: 544 return character.RenderedData( 545 net=self._net, 546 customization=self.deserialize_character_customization( 547 payload["customization"] 548 ), 549 custom_dyes=[ 550 self.deserialize_character_dye(dye) 551 for dye in payload["customDyes"] 552 if dye 553 ], 554 equipment=[ 555 self.deserialize_character_minimal_equipments(equipment) 556 for equipment in payload["peerView"]["equipment"] 557 ], 558 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
560 def deserialize_available_activity( 561 self, payload: typedefs.JSONObject 562 ) -> activity.AvailableActivity: 563 return activity.AvailableActivity( 564 hash=payload["activityHash"], 565 is_new=payload["isNew"], 566 is_completed=payload["isCompleted"], 567 is_visible=payload["isVisible"], 568 display_level=payload.get("displayLevel"), 569 recommended_light=payload.get("recommendedLight"), 570 difficulty=activity.Difficulty(payload["difficultyTier"]), 571 can_join=payload["canJoin"], 572 can_lead=payload["canLead"], 573 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
575 def deserialize_character_activity( 576 self, payload: typedefs.JSONObject 577 ) -> activity.CharacterActivity: 578 current_mode: enums.GameMode | None = None 579 if raw_current_mode := payload.get("currentActivityModeType"): 580 current_mode = enums.GameMode(raw_current_mode) 581 582 if raw_current_modes := payload.get("currentActivityModeTypes"): 583 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 584 else: 585 current_mode_types = [] 586 587 return activity.CharacterActivity( 588 date_started=time.clean_date(payload["dateActivityStarted"]), 589 current_hash=payload["currentActivityHash"], 590 current_mode_hash=payload["currentActivityModeHash"], 591 current_mode=current_mode, 592 current_mode_hashes=payload.get("currentActivityModeHashes", []), 593 current_mode_types=current_mode_types, 594 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 595 last_story_hash=payload["lastCompletedStoryHash"], 596 available_activities=[ 597 self.deserialize_available_activity(activity_) 598 for activity_ in payload["availableActivities"] 599 ], 600 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
602 def deserialize_profile_items( 603 self, payload: typedefs.JSONObject, / 604 ) -> list[profile.ProfileItemImpl]: 605 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ProfileItemImpl]: A profile component object that contains items of the deserialized payload.
648 def deserialize_progressions( 649 self, payload: typedefs.JSONObject 650 ) -> progressions.Progression: 651 return progressions.Progression( 652 hash=int(payload["progressionHash"]), 653 level=int(payload["level"]), 654 cap=int(payload["levelCap"]), 655 daily_limit=int(payload["dailyLimit"]), 656 weekly_limit=int(payload["weeklyLimit"]), 657 current_progress=int(payload["currentProgress"]), 658 daily_progress=int(payload["dailyProgress"]), 659 needed=int(payload["progressToNextLevel"]), 660 next_level=int(payload["nextLevelAt"]), 661 )
746 def deserialize_milestone( 747 self, payload: typedefs.JSONObject 748 ) -> milestones.Milestone: 749 start_date: datetime.datetime | None = None 750 if raw_start_date := payload.get("startDate"): 751 start_date = time.clean_date(raw_start_date) 752 753 end_date: datetime.datetime | None = None 754 if raw_end_date := payload.get("endDate"): 755 end_date = time.clean_date(raw_end_date) 756 757 rewards: collections.Collection[milestones.MilestoneReward] | None = None 758 if raw_rewards := payload.get("rewards"): 759 rewards = [ 760 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 761 ] 762 763 activities: collections.Sequence[milestones.MilestoneActivity] | None = None 764 if raw_activities := payload.get("activities"): 765 activities = [ 766 self._deserialize_milestone_activity(active) 767 for active in raw_activities 768 ] 769 770 quests: collections.Sequence[milestones.MilestoneQuest] | None = None 771 if raw_quests := payload.get("availableQuests"): 772 quests = [ 773 self._deserialize_milestone_available_quest(quest) 774 for quest in raw_quests 775 ] 776 777 vendors: collections.Sequence[milestones.MilestoneVendor] | None = None 778 if raw_vendors := payload.get("vendors"): 779 vendors = [ 780 milestones.MilestoneVendor( 781 vendor_hash=vendor["vendorHash"], 782 preview_itemhash=vendor.get("previewItemHash"), 783 ) 784 for vendor in raw_vendors 785 ] 786 787 return milestones.Milestone( 788 hash=payload["milestoneHash"], 789 start_date=start_date, 790 end_date=end_date, 791 order=payload["order"], 792 rewards=rewards, 793 available_quests=quests, 794 activities=activities, 795 vendors=vendors, 796 )
850 def deserialize_character_progressions( 851 self, payload: typedefs.JSONObject 852 ) -> character.CharacterProgression: 853 progressions_ = { 854 int(prog_id): self.deserialize_progressions(prog) 855 for prog_id, prog in payload["progressions"].items() 856 } 857 858 factions = { 859 int(faction_id): self._deserialize_factions(faction) 860 for faction_id, faction in payload["factions"].items() 861 } 862 863 milestones_ = { 864 int(milestone_hash): self.deserialize_milestone(milestone) 865 for milestone_hash, milestone in payload["milestones"].items() 866 } 867 868 uninstanced_item_objectives = { 869 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 870 for item_hash, obj in payload["uninstancedItemObjectives"].items() 871 } 872 873 artifact = payload["seasonalArtifact"] 874 seasonal_artifact = season.CharacterScopedArtifact( 875 hash=artifact["artifactHash"], 876 points_used=artifact["pointsUsed"], 877 reset_count=artifact["resetCount"], 878 tiers=[ 879 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 880 ], 881 ) 882 checklists = payload["checklists"] 883 884 return character.CharacterProgression( 885 progressions=progressions_, 886 factions=factions, 887 checklists=checklists, 888 milestones=milestones_, 889 seasonal_artifact=seasonal_artifact, 890 uninstanced_item_objectives=uninstanced_item_objectives, 891 )
893 def deserialize_character_progressions_mapping( 894 self, payload: typedefs.JSONObject 895 ) -> collections.Mapping[int, character.CharacterProgression]: 896 character_progressions: collections.Mapping[ 897 int, character.CharacterProgression 898 ] = {} 899 for char_id, data in payload["data"].items(): 900 # A little hack to stop mypy complaining about Mapping <-> dict 901 character_progressions[ 902 int(char_id) 903 ] = self.deserialize_character_progressions(data) # type: ignore[index] 904 return character_progressions
906 def deserialize_characters_records( 907 self, 908 payload: typedefs.JSONObject, 909 ) -> collections.Mapping[int, records.CharacterRecord]: 910 return { 911 int(rec_id): self.deserialize_character_records( 912 rec, record_hashes=payload.get("featuredRecordHashes") 913 ) 914 for rec_id, rec in payload["records"].items() 915 }
917 def deserialize_profile_records( 918 self, payload: typedefs.JSONObject 919 ) -> collections.Mapping[int, records.Record]: 920 raw_profile_records = payload["data"] 921 scores = records.RecordScores( 922 current_score=raw_profile_records["score"], 923 legacy_score=raw_profile_records["legacyScore"], 924 lifetime_score=raw_profile_records["lifetimeScore"], 925 ) 926 return { 927 int(record_id): self.deserialize_records( 928 record, 929 scores, 930 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 931 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 932 ) 933 for record_id, record in raw_profile_records["records"].items() 934 }
969 def deserialize_craftables_component( 970 self, payload: typedefs.JSONObject 971 ) -> components.CraftablesComponent: 972 return components.CraftablesComponent( 973 net=self._net, 974 craftables={ 975 int(item_id): self._deserialize_craftable_item(item) 976 for item_id, item in payload["craftables"].items() 977 if item is not None 978 }, 979 crafting_root_node_hash=payload["craftingRootNodeHash"], 980 )
982 def deserialize_components( # noqa: C901 Too complex. 983 self, payload: typedefs.JSONObject 984 ) -> components.Component: 985 # Due to how complex this method is, We'll stick to 986 # typing.Optional here. 987 988 profile_: profile.Profile | None = None 989 if raw_profile := payload.get("profile"): 990 profile_ = self.deserialize_profile(raw_profile) 991 992 profile_progression: profile.ProfileProgression | None = None 993 if raw_profile_progression := payload.get("profileProgression"): 994 profile_progression = self.deserialize_profile_progression( 995 raw_profile_progression 996 ) 997 998 profile_currencies: typing.Optional[ 999 collections.Sequence[profile.ProfileItemImpl] 1000 ] = None 1001 if raw_profile_currencies := payload.get("profileCurrencies"): 1002 if "data" in raw_profile_currencies: 1003 profile_currencies = self.deserialize_profile_items( 1004 raw_profile_currencies["data"] 1005 ) 1006 1007 profile_inventories: typing.Optional[ 1008 collections.Sequence[profile.ProfileItemImpl] 1009 ] = None 1010 if raw_profile_inventories := payload.get("profileInventory"): 1011 if "data" in raw_profile_inventories: 1012 profile_inventories = self.deserialize_profile_items( 1013 raw_profile_inventories["data"] 1014 ) 1015 1016 profile_records: typing.Optional[ 1017 collections.Mapping[int, records.Record] 1018 ] = None 1019 1020 if raw_profile_records_ := payload.get("profileRecords"): 1021 profile_records = self.deserialize_profile_records(raw_profile_records_) 1022 1023 characters: typing.Optional[ 1024 collections.Mapping[int, character.Character] 1025 ] = None 1026 if raw_characters := payload.get("characters"): 1027 characters = self.deserialize_characters(raw_characters) 1028 1029 character_records: typing.Optional[ 1030 collections.Mapping[int, records.CharacterRecord] 1031 ] = None 1032 1033 if raw_character_records := payload.get("characterRecords"): 1034 # Had to do it in two steps.. 1035 to_update = {} 1036 for _, data in raw_character_records["data"].items(): 1037 for record_id, record in data.items(): 1038 to_update[record_id] = record 1039 1040 character_records = { 1041 int(rec_id): self.deserialize_character_records( 1042 rec, record_hashes=to_update.get("featuredRecordHashes") 1043 ) 1044 for rec_id, rec in to_update["records"].items() 1045 } 1046 1047 character_equipments: typing.Optional[ 1048 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1049 ] = None 1050 if raw_character_equips := payload.get("characterEquipment"): 1051 character_equipments = self.deserialize_character_equipments( 1052 raw_character_equips 1053 ) 1054 1055 character_inventories: typing.Optional[ 1056 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1057 ] = None 1058 if raw_character_inventories := payload.get("characterInventories"): 1059 if "data" in raw_character_inventories: 1060 character_inventories = self.deserialize_character_equipments( 1061 raw_character_inventories 1062 ) 1063 1064 character_activities: typing.Optional[ 1065 collections.Mapping[int, activity.CharacterActivity] 1066 ] = None 1067 if raw_char_acts := payload.get("characterActivities"): 1068 character_activities = self.deserialize_character_activities(raw_char_acts) 1069 1070 character_render_data: typing.Optional[ 1071 collections.Mapping[int, character.RenderedData] 1072 ] = None 1073 if raw_character_render_data := payload.get("characterRenderData"): 1074 character_render_data = self.deserialize_characters_render_data( 1075 raw_character_render_data 1076 ) 1077 1078 character_progressions: typing.Optional[ 1079 collections.Mapping[int, character.CharacterProgression] 1080 ] = None 1081 1082 if raw_character_progressions := payload.get("characterProgressions"): 1083 character_progressions = self.deserialize_character_progressions_mapping( 1084 raw_character_progressions 1085 ) 1086 1087 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1088 if raw_profile_string_vars := payload.get("profileStringVariables"): 1089 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1090 1091 character_string_vars: typing.Optional[ 1092 collections.Mapping[int, collections.Mapping[int, int]] 1093 ] = None 1094 if raw_character_string_vars := payload.get("characterStringVariables"): 1095 character_string_vars = { 1096 int(char_id): data["integerValuesByHash"] 1097 for char_id, data in raw_character_string_vars["data"].items() 1098 } 1099 1100 metrics: typing.Optional[ 1101 collections.Sequence[ 1102 collections.Mapping[int, tuple[bool, records.Objective | None]] 1103 ] 1104 ] = None 1105 root_node_hash: int | None = None 1106 1107 if raw_metrics := payload.get("metrics"): 1108 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1109 metrics = [ 1110 { 1111 int(metrics_hash): ( 1112 data["invisible"], 1113 self.deserialize_objectives(data["objectiveProgress"]) 1114 if "objectiveProgress" in data 1115 else None, 1116 ) 1117 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1118 } 1119 ] 1120 transitory: fireteams.FireteamParty | None = None 1121 if raw_transitory := payload.get("profileTransitoryData"): 1122 if "data" in raw_transitory: 1123 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1124 1125 item_components: components.ItemsComponent | None = None 1126 if raw_item_components := payload.get("itemComponents"): 1127 item_components = self.deserialize_items_component(raw_item_components) 1128 1129 profile_plugsets: typing.Optional[ 1130 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1131 ] = None 1132 1133 if raw_profile_plugs := payload.get("profilePlugSets"): 1134 profile_plugsets = { 1135 int(index): [self.deserialize_plug_item_state(state) for state in data] 1136 for index, data in raw_profile_plugs["data"]["plugs"].items() 1137 } 1138 1139 character_plugsets: typing.Optional[ 1140 collections.Mapping[ 1141 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1142 ] 1143 ] = None 1144 if raw_char_plugsets := payload.get("characterPlugSets"): 1145 character_plugsets = { 1146 int(char_id): { 1147 int(index): [ 1148 self.deserialize_plug_item_state(state) for state in data 1149 ] 1150 for index, data in inner["plugs"].items() 1151 } 1152 for char_id, inner in raw_char_plugsets["data"].items() 1153 } 1154 1155 character_collectibles: typing.Optional[ 1156 collections.Mapping[int, items.Collectible] 1157 ] = None 1158 if raw_character_collectibles := payload.get("characterCollectibles"): 1159 character_collectibles = { 1160 int(char_id): self._deserialize_collectible(data) 1161 for char_id, data in raw_character_collectibles["data"].items() 1162 } 1163 1164 profile_collectibles: items.Collectible | None = None 1165 if raw_profile_collectibles := payload.get("profileCollectibles"): 1166 profile_collectibles = self._deserialize_collectible( 1167 raw_profile_collectibles["data"] 1168 ) 1169 1170 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1171 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1172 profile_nodes = { 1173 int(node_hash): self._deserialize_node(node) 1174 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1175 } 1176 1177 character_nodes: typing.Optional[ 1178 collections.Mapping[int, collections.Mapping[int, records.Node]] 1179 ] = None 1180 if raw_character_nodes := payload.get("characterPresentationNodes"): 1181 character_nodes = { 1182 int(char_id): { 1183 int(node_hash): self._deserialize_node(node) 1184 for node_hash, node in each_character["nodes"].items() 1185 } 1186 for char_id, each_character in raw_character_nodes["data"].items() 1187 } 1188 1189 platform_silver: typing.Optional[ 1190 collections.Mapping[str, profile.ProfileItemImpl] 1191 ] = None 1192 if raw_platform_silver := payload.get("platformSilver"): 1193 if "data" in raw_platform_silver: 1194 platform_silver = { 1195 platform_name: self.deserialize_profile_item(item) 1196 for platform_name, item in raw_platform_silver["data"][ 1197 "platformSilver" 1198 ].items() 1199 } 1200 1201 character_currency_lookups: typing.Optional[ 1202 collections.Mapping[int, collections.Sequence[items.Currency]] 1203 ] = None 1204 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1205 if "data" in raw_char_lookups: 1206 character_currency_lookups = { 1207 int(char_id): self._deserialize_currencies(currency) 1208 for char_id, currency in raw_char_lookups["data"].items() 1209 } 1210 1211 character_craftables: typing.Optional[ 1212 collections.Mapping[int, components.CraftablesComponent] 1213 ] = None 1214 if raw_character_craftables := payload.get("characterCraftables"): 1215 if "data" in raw_character_craftables: 1216 character_craftables = { 1217 int(char_id): self.deserialize_craftables_component(craftable) 1218 for char_id, craftable in raw_character_craftables["data"].items() 1219 } 1220 1221 return components.Component( 1222 profiles=profile_, 1223 profile_progression=profile_progression, 1224 profile_currencies=profile_currencies, 1225 profile_inventories=profile_inventories, 1226 profile_records=profile_records, 1227 characters=characters, 1228 character_records=character_records, 1229 character_equipments=character_equipments, 1230 character_inventories=character_inventories, 1231 character_activities=character_activities, 1232 character_render_data=character_render_data, 1233 character_progressions=character_progressions, 1234 profile_string_variables=profile_string_vars, 1235 character_string_variables=character_string_vars, 1236 metrics=metrics, 1237 root_node_hash=root_node_hash, 1238 transitory=transitory, 1239 item_components=item_components, 1240 profile_plugsets=profile_plugsets, 1241 character_plugsets=character_plugsets, 1242 character_collectibles=character_collectibles, 1243 profile_collectibles=profile_collectibles, 1244 profile_nodes=profile_nodes, 1245 character_nodes=character_nodes, 1246 platform_silver=platform_silver, 1247 character_currency_lookups=character_currency_lookups, 1248 character_craftables=character_craftables, 1249 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1251 def deserialize_items_component( 1252 self, payload: typedefs.JSONObject 1253 ) -> components.ItemsComponent: 1254 # Due to how complex this method is, We'll stick to typing.Optional. 1255 instances: typing.Optional[ 1256 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1257 ] = None 1258 if raw_instances := payload.get("instances"): 1259 instances = [ 1260 { 1261 int(ins_id): self.deserialize_instanced_item(item) 1262 for ins_id, item in raw_instances["data"].items() 1263 } 1264 ] 1265 1266 render_data: typing.Optional[ 1267 collections.Mapping[int, tuple[bool, dict[int, int]]] 1268 ] = None 1269 if raw_render_data := payload.get("renderData"): 1270 render_data = { 1271 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1272 for ins_id, data in raw_render_data["data"].items() 1273 } 1274 1275 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1276 if raw_stats := payload.get("stats"): 1277 builder: collections.Mapping[int, items.ItemStatsView] = {} 1278 for ins_id, stat in raw_stats["data"].items(): 1279 for _, items_ in stat.items(): 1280 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1281 stats = builder 1282 1283 sockets: typing.Optional[ 1284 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1285 ] = None 1286 if raw_sockets := payload.get("sockets"): 1287 sockets = { 1288 int(ins_id): [ 1289 self.deserialize_item_socket(socket) for socket in item["sockets"] 1290 ] 1291 for ins_id, item in raw_sockets["data"].items() 1292 } 1293 1294 objectives: typing.Optional[ 1295 collections.Mapping[int, collections.Sequence[records.Objective]] 1296 ] = None 1297 if raw_objectives := payload.get("objectives"): 1298 objectives = { 1299 int(ins_id): [self.deserialize_objectives(objective)] 1300 for ins_id, data in raw_objectives["data"].items() 1301 for objective in data["objectives"] 1302 } 1303 1304 perks: typing.Optional[ 1305 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1306 ] = None 1307 if raw_perks := payload.get("perks"): 1308 perks = { 1309 int(ins_id): [ 1310 self.deserialize_item_perk(perk) for perk in item["perks"] 1311 ] 1312 for ins_id, item in raw_perks["data"].items() 1313 } 1314 1315 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1316 if raw_plug_states := payload.get("plugStates"): 1317 pending_states: list[items.PlugItemState] = [] 1318 for _, plug in raw_plug_states["data"].items(): 1319 pending_states.append(self.deserialize_plug_item_state(plug)) 1320 plug_states = pending_states 1321 1322 reusable_plugs: typing.Optional[ 1323 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1324 ] = None 1325 if raw_re_plugs := payload.get("reusablePlugs"): 1326 reusable_plugs = { 1327 int(ins_id): [ 1328 self.deserialize_plug_item_state(state) for state in inner 1329 ] 1330 for ins_id, plug in raw_re_plugs["data"].items() 1331 for inner in list(plug["plugs"].values()) 1332 } 1333 1334 plug_objectives: typing.Optional[ 1335 collections.Mapping[ 1336 int, collections.Mapping[int, collections.Collection[records.Objective]] 1337 ] 1338 ] = None 1339 if raw_plug_objectives := payload.get("plugObjectives"): 1340 plug_objectives = { 1341 int(ins_id): { 1342 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1343 for obj_hash, objs in inner["objectivesPerPlug"].items() 1344 } 1345 for ins_id, inner in raw_plug_objectives["data"].items() 1346 } 1347 1348 return components.ItemsComponent( 1349 sockets=sockets, 1350 stats=stats, 1351 render_data=render_data, 1352 instances=instances, 1353 objectives=objectives, 1354 perks=perks, 1355 plug_states=plug_states, 1356 reusable_plugs=reusable_plugs, 1357 plug_objectives=plug_objectives, 1358 )
Deserialize a JSON objects within the itemComponents key.`
1360 def deserialize_character_component( # type: ignore[call-arg] 1361 self, payload: typedefs.JSONObject 1362 ) -> components.CharacterComponent: 1363 character_: character.Character | None = None 1364 if raw_singular_character := payload.get("character"): 1365 character_ = self.deserialize_character(raw_singular_character["data"]) 1366 1367 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1368 if raw_inventory := payload.get("inventory"): 1369 if "data" in raw_inventory: 1370 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1371 1372 activities: activity.CharacterActivity | None = None 1373 if raw_activities := payload.get("activities"): 1374 activities = self.deserialize_character_activity(raw_activities["data"]) 1375 1376 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1377 if raw_equipments := payload.get("equipment"): 1378 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1379 1380 progressions_: character.CharacterProgression | None = None 1381 if raw_progressions := payload.get("progressions"): 1382 progressions_ = self.deserialize_character_progressions( 1383 raw_progressions["data"] 1384 ) 1385 1386 render_data: character.RenderedData | None = None 1387 if raw_render_data := payload.get("renderData"): 1388 render_data = self.deserialize_character_render_data( 1389 raw_render_data["data"] 1390 ) 1391 1392 character_records: typing.Optional[ 1393 collections.Mapping[int, records.CharacterRecord] 1394 ] = None 1395 if raw_char_records := payload.get("records"): 1396 character_records = self.deserialize_characters_records( 1397 raw_char_records["data"] 1398 ) 1399 1400 item_components: components.ItemsComponent | None = None 1401 if raw_item_components := payload.get("itemComponents"): 1402 item_components = self.deserialize_items_component(raw_item_components) 1403 1404 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1405 if raw_nodes := payload.get("presentationNodes"): 1406 nodes = { 1407 int(node_hash): self._deserialize_node(node) 1408 for node_hash, node in raw_nodes["data"]["nodes"].items() 1409 } 1410 1411 collectibles: items.Collectible | None = None 1412 if raw_collectibles := payload.get("collectibles"): 1413 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1414 1415 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1416 if raw_currencies := payload.get("currencyLookups"): 1417 if "data" in raw_currencies: 1418 currency_lookups = self._deserialize_currencies(raw_currencies) 1419 1420 return components.CharacterComponent( 1421 activities=activities, 1422 equipment=equipment, 1423 inventory=inventory, 1424 progressions=progressions_, 1425 render_data=render_data, 1426 character=character_, 1427 character_records=character_records, 1428 profile_records=None, 1429 item_components=item_components, 1430 currency_lookups=currency_lookups, 1431 collectibles=collectibles, 1432 nodes=nodes, 1433 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1452 def deserialize_inventory_results( 1453 self, payload: typedefs.JSONObject 1454 ) -> iterators.Iterator[entity.SearchableEntity]: 1455 return iterators.Iterator( 1456 [ 1457 entity.SearchableEntity( 1458 net=self._net, 1459 hash=data["hash"], 1460 entity_type=data["entityType"], 1461 weight=data["weight"], 1462 suggested_words=payload["suggestedWords"], 1463 name=data["displayProperties"]["name"], 1464 has_icon=data["displayProperties"]["hasIcon"], 1465 description=typedefs.unknown( 1466 data["displayProperties"]["description"] 1467 ), 1468 icon=assets.Image(data["displayProperties"]["icon"]), 1469 ) 1470 for data in payload["results"]["results"] 1471 ] 1472 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1501 def deserialize_inventory_entity( # noqa: C901 Too complex. 1502 self, payload: typedefs.JSONObject, / 1503 ) -> entity.InventoryEntity: 1504 props = self._set_entity_attrs(payload) 1505 objects = self._deserialize_inventory_item_objects(payload) 1506 1507 collectible_hash: int | None = None 1508 if raw_collectible_hash := payload.get("collectibleHash"): 1509 collectible_hash = int(raw_collectible_hash) 1510 1511 secondary_icon: assets.Image | None = None 1512 if raw_second_icon := payload.get("secondaryIcon"): 1513 secondary_icon = assets.Image(raw_second_icon) 1514 1515 secondary_overlay: assets.Image | None = None 1516 if raw_second_overlay := payload.get("secondaryOverlay"): 1517 secondary_overlay = assets.Image(raw_second_overlay) 1518 1519 secondary_special: assets.Image | None = None 1520 if raw_second_special := payload.get("secondarySpecial"): 1521 secondary_special = assets.Image(raw_second_special) 1522 1523 screenshot: assets.Image | None = None 1524 if raw_screenshot := payload.get("screenshot"): 1525 screenshot = assets.Image(raw_screenshot) 1526 1527 watermark_icon: assets.Image | None = None 1528 if raw_watermark_icon := payload.get("iconWatermark"): 1529 watermark_icon = assets.Image(raw_watermark_icon) 1530 1531 watermark_shelved: assets.Image | None = None 1532 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1533 watermark_shelved = assets.Image(raw_watermark_shelved) 1534 1535 about: str | None = None 1536 if raw_about := payload.get("flavorText"): 1537 about = raw_about 1538 1539 ui_item_style: str | None = None 1540 if raw_ui_style := payload.get("uiItemDisplayStyle"): 1541 ui_item_style = raw_ui_style 1542 1543 tier_and_name: str | None = None 1544 if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"): 1545 tier_and_name = raw_tier_and_name 1546 1547 type_name: str | None = None 1548 if raw_type_name := payload.get("itemTypeDisplayName"): 1549 type_name = raw_type_name 1550 1551 display_source: str | None = None 1552 if raw_display_source := payload.get("displaySource"): 1553 display_source = raw_display_source 1554 1555 lorehash: int | None = None 1556 if raw_lore_hash := payload.get("loreHash"): 1557 lorehash = int(raw_lore_hash) 1558 1559 summary_hash: int | None = None 1560 if raw_summary_hash := payload.get("summaryItemHash"): 1561 summary_hash = raw_summary_hash 1562 1563 breaker_type_hash: int | None = None 1564 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1565 breaker_type_hash = int(raw_breaker_type_hash) 1566 1567 damage_types: typing.Optional[collections.Sequence[int]] = None 1568 if raw_damage_types := payload.get("damageTypes"): 1569 damage_types = [int(type_) for type_ in raw_damage_types] 1570 1571 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1572 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1573 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1574 1575 default_damagetype_hash: int | None = None 1576 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1577 default_damagetype_hash = int(raw_defaultdmg_hash) 1578 1579 emblem_objective_hash: int | None = None 1580 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1581 emblem_objective_hash = int(raw_emblem_obj_hash) 1582 1583 tier_type: enums.TierType | None = None 1584 tier: enums.ItemTier | None = None 1585 bucket_hash: int | None = None 1586 recovery_hash: int | None = None 1587 tier_name: str | None = None 1588 isinstance_item: bool = False 1589 expire_tool_tip: str | None = None 1590 expire_in_orbit_message: str | None = None 1591 suppress_expiration: bool = False 1592 max_stack_size: int | None = None 1593 stack_label: str | None = None 1594 1595 if inventory := payload.get("inventory"): 1596 tier_type = enums.TierType(int(inventory["tierType"])) 1597 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1598 bucket_hash = int(inventory["bucketTypeHash"]) 1599 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1600 tier_name = inventory["tierTypeName"] 1601 isinstance_item = inventory["isInstanceItem"] 1602 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1603 max_stack_size = int(inventory["maxStackSize"]) 1604 1605 try: 1606 stack_label = inventory["stackUniqueLabel"] 1607 except KeyError: 1608 pass 1609 1610 return entity.InventoryEntity( 1611 net=self._net, 1612 collectible_hash=collectible_hash, 1613 name=props.name, 1614 about=about, 1615 emblem_objective_hash=emblem_objective_hash, 1616 suppress_expiration=suppress_expiration, 1617 max_stack_size=max_stack_size, 1618 stack_label=stack_label, 1619 tier=tier, 1620 tier_type=tier_type, 1621 tier_name=tier_name, 1622 bucket_hash=bucket_hash, 1623 recovery_bucket_hash=recovery_hash, 1624 isinstance_item=isinstance_item, 1625 expire_in_orbit_message=expire_in_orbit_message, 1626 expiration_tooltip=expire_tool_tip, 1627 lore_hash=lorehash, 1628 type_and_tier_name=tier_and_name, 1629 summary_hash=summary_hash, 1630 ui_display_style=ui_item_style, 1631 type_name=type_name, 1632 breaker_type_hash=breaker_type_hash, 1633 description=props.description, 1634 display_source=display_source, 1635 hash=props.hash, 1636 damage_types=damage_types, 1637 index=props.index, 1638 icon=props.icon, 1639 has_icon=props.has_icon, 1640 screenshot=screenshot, 1641 watermark_icon=watermark_icon, 1642 watermark_shelved=watermark_shelved, 1643 secondary_icon=secondary_icon, 1644 secondary_overlay=secondary_overlay, 1645 secondary_special=secondary_special, 1646 type=enums.ItemType(int(payload["itemType"])), 1647 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1648 trait_ids=[trait for trait in payload.get("traitIds", [])], 1649 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1650 item_class=enums.Class(int(payload["classType"])), 1651 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1652 breaker_type=int(payload["breakerType"]), 1653 default_damagetype=int(payload["defaultDamageType"]), 1654 default_damagetype_hash=default_damagetype_hash, 1655 damagetype_hashes=damagetype_hashes, 1656 tooltip_notifications=payload["tooltipNotifications"], 1657 not_transferable=payload["nonTransferrable"], 1658 allow_actions=payload["allowActions"], 1659 is_equippable=payload["equippable"], 1660 objects=objects, 1661 background_colors=payload.get("backgroundColor", {}), 1662 season_hash=payload.get("seasonHash"), 1663 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1664 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1666 def deserialize_objective_entity( 1667 self, payload: typedefs.JSONObject, / 1668 ) -> entity.ObjectiveEntity: 1669 props = self._set_entity_attrs(payload) 1670 return entity.ObjectiveEntity( 1671 net=self._net, 1672 hash=props.hash, 1673 index=props.index, 1674 description=props.description, 1675 name=props.name, 1676 has_icon=props.has_icon, 1677 icon=props.icon, 1678 unlock_value_hash=payload["unlockValueHash"], 1679 completion_value=payload["completionValue"], 1680 scope=entity.GatingScope(int(payload["scope"])), 1681 location_hash=payload["locationHash"], 1682 allowed_negative_value=payload["allowNegativeValue"], 1683 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1684 counting_downward=payload["isCountingDownward"], 1685 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1686 progress_description=payload["progressDescription"], 1687 perks=payload["perks"], 1688 stats=payload["stats"], 1689 minimum_visibility=payload["minimumVisibilityThreshold"], 1690 allow_over_completion=payload["allowOvercompletion"], 1691 show_value_style=payload["showValueOnComplete"], 1692 display_only_objective=payload["isDisplayOnlyObjective"], 1693 complete_value_style=entity.ValueUIStyle( 1694 int(payload["completedValueStyle"]) 1695 ), 1696 progress_value_style=entity.ValueUIStyle( 1697 int(payload["inProgressValueStyle"]) 1698 ), 1699 ui_label=payload["uiLabel"], 1700 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1701 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1729 def deserialize_activity( 1730 self, 1731 payload: typedefs.JSONObject, 1732 /, 1733 ) -> activity.Activity: 1734 period = time.clean_date(payload["period"]) 1735 details = payload["activityDetails"] 1736 ref_id = int(details["referenceId"]) 1737 instance_id = int(details["instanceId"]) 1738 mode = enums.GameMode(details["mode"]) 1739 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1740 is_private = details["isPrivate"] 1741 membership_type = enums.MembershipType(int(details["membershipType"])) 1742 1743 # Since we're using the same fields for post activity method 1744 # this check is required since post activity doesn't values values 1745 values = self._deserialize_activity_values(payload["values"]) 1746 1747 return activity.Activity( 1748 net=self._net, 1749 hash=ref_id, 1750 instance_id=instance_id, 1751 mode=mode, 1752 modes=modes, 1753 is_private=is_private, 1754 membership_type=membership_type, 1755 occurred_at=period, 1756 values=values, 1757 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1759 def deserialize_activities( 1760 self, payload: typedefs.JSONObject 1761 ) -> iterators.Iterator[activity.Activity]: 1762 return iterators.Iterator( 1763 [ 1764 self.deserialize_activity(activity_) 1765 for activity_ in payload["activities"] 1766 ] 1767 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.Iterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1769 def deserialize_extended_weapon_values( 1770 self, payload: typedefs.JSONObject 1771 ) -> activity.ExtendedWeaponValues: 1772 assists: int | None = None 1773 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1774 assists = raw_assists["basic"]["value"] 1775 assists_damage: int | None = None 1776 1777 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1778 assists_damage = raw_assists_damage["basic"]["value"] 1779 1780 return activity.ExtendedWeaponValues( 1781 reference_id=int(payload["referenceId"]), 1782 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1783 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1784 "value" 1785 ], 1786 assists=assists, 1787 assists_damage=assists_damage, 1788 precision_kills_percentage=( 1789 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1790 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1791 "displayValue" 1792 ], 1793 ), 1794 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1815 def deserialize_post_activity_player( 1816 self, payload: typedefs.JSONObject, / 1817 ) -> activity.PostActivityPlayer: 1818 player = payload["player"] 1819 1820 class_hash: int | None = None 1821 if (class_hash := player.get("classHash")) is not None: 1822 class_hash = class_hash 1823 1824 race_hash: int | None = None 1825 if (race_hash := player.get("raceHash")) is not None: 1826 race_hash = race_hash 1827 1828 gender_hash: int | None = None 1829 if (gender_hash := player.get("genderHash")) is not None: 1830 gender_hash = gender_hash 1831 1832 character_class: str | None = None 1833 if character_class := player.get("characterClass"): 1834 character_class = character_class 1835 1836 character_level: int | None = None 1837 if (character_level := player.get("characterLevel")) is not None: 1838 character_level = character_level 1839 1840 return activity.PostActivityPlayer( 1841 standing=int(payload["standing"]), 1842 score=int(payload["score"]["basic"]["value"]), 1843 character_id=payload["characterId"], 1844 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1845 character_class=character_class, 1846 character_level=character_level, 1847 race_hash=race_hash, 1848 gender_hash=gender_hash, 1849 class_hash=class_hash, 1850 light_level=int(player["lightLevel"]), 1851 emblem_hash=int(player["emblemHash"]), 1852 values=self._deserialize_activity_values(payload["values"]), 1853 extended_values=self._deserialize_extended_values(payload["extended"]), 1854 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1866 def deserialize_post_activity( 1867 self, payload: typedefs.JSONObject 1868 ) -> activity.PostActivity: 1869 period = time.clean_date(payload["period"]) 1870 details = payload["activityDetails"] 1871 ref_id = int(details["referenceId"]) 1872 instance_id = int(details["instanceId"]) 1873 mode = enums.GameMode(details["mode"]) 1874 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1875 is_private = details["isPrivate"] 1876 membership_type = enums.MembershipType(int(details["membershipType"])) 1877 return activity.PostActivity( 1878 net=self._net, 1879 hash=ref_id, 1880 membership_type=membership_type, 1881 instance_id=instance_id, 1882 mode=mode, 1883 modes=modes, 1884 is_private=is_private, 1885 occurred_at=period, 1886 starting_phase=int(payload["startingPhaseIndex"]), 1887 players=[ 1888 self.deserialize_post_activity_player(player) 1889 for player in payload["entries"] 1890 ], 1891 teams=[ 1892 self._deserialize_post_activity_team(team) for team in payload["teams"] 1893 ], 1894 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1932 def deserialize_aggregated_activity( 1933 self, payload: typedefs.JSONObject 1934 ) -> activity.AggregatedActivity: 1935 return activity.AggregatedActivity( 1936 hash=int(payload["activityHash"]), 1937 values=self._deserialize_aggregated_activity_values(payload["values"]), 1938 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
1940 def deserialize_aggregated_activities( 1941 self, payload: typedefs.JSONObject 1942 ) -> iterators.Iterator[activity.AggregatedActivity]: 1943 return iterators.Iterator( 1944 [ 1945 self.deserialize_aggregated_activity(activity) 1946 for activity in payload["activities"] 1947 ] 1948 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.Iterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
1950 def deserialize_linked_profiles( 1951 self, payload: typedefs.JSONObject 1952 ) -> profile.LinkedProfile: 1953 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 1954 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1955 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1956 1957 if raw_profile := payload.get("profiles"): 1958 for pfile in raw_profile: 1959 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 1960 1961 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 1962 for raw_error_pfile in raw_profiles_with_errors: 1963 if error_pfile := raw_error_pfile.get("infoCard"): 1964 error_profiles_vec.append( 1965 self.deserialize_destiny_membership(error_pfile) 1966 ) 1967 1968 return profile.LinkedProfile( 1969 bungie_user=bungie_user, 1970 profiles=profiles_vec, 1971 profiles_with_errors=error_profiles_vec, 1972 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
1988 def deserialize_public_milestone_content( 1989 self, payload: typedefs.JSONObject 1990 ) -> milestones.MilestoneContent: 1991 items_categories: milestones.MilestoneItems | None = None 1992 1993 if raw_categories := payload.get("itemCategories"): 1994 for item in raw_categories: 1995 title: str | None = None 1996 if raw_title := item.get("title"): 1997 title = raw_title 1998 if raw_hashes := item.get("itemHashes"): 1999 hashes = raw_hashes 2000 2001 items_categories = milestones.MilestoneItems(title=title, hashes=hashes) 2002 2003 tips: typing.MutableSequence[str] = [] 2004 if raw_tips := payload.get("tips"): 2005 tips = raw_tips 2006 2007 return milestones.MilestoneContent( 2008 about=typedefs.unknown(payload["about"]), 2009 status=typedefs.unknown(payload["status"]), 2010 tips=tips, 2011 items=items_categories, 2012 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2014 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2015 bungie_user: user.BungieUser | None = None 2016 2017 if raw_bungie_user := payload.get("bungieNetUser"): 2018 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2019 2020 return friends.Friend( 2021 net=self._net, 2022 id=int(payload["lastSeenAsMembershipId"]), 2023 name=typedefs.unknown(payload["bungieGlobalDisplayName"]), 2024 code=payload.get("bungieGlobalDisplayNameCode"), 2025 relationship=enums.Relationship(payload["relationship"]), 2026 user=bungie_user, 2027 online_status=enums.Presence(payload["onlineStatus"]), 2028 online_title=payload["onlineTitle"], 2029 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2030 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2032 def deserialize_friends( 2033 self, payload: typedefs.JSONObject 2034 ) -> collections.Sequence[friends.Friend]: 2035 mut_seq: typing.MutableSequence[friends.Friend] = [] 2036 if raw_friends := payload.get("friends"): 2037 for friend in raw_friends: 2038 mut_seq.append(self.deserialize_friend(friend)) 2039 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2041 def deserialize_friend_requests( 2042 self, payload: typedefs.JSONObject 2043 ) -> friends.FriendRequestView: 2044 incoming: typing.MutableSequence[friends.Friend] = [] 2045 outgoing: typing.MutableSequence[friends.Friend] = [] 2046 2047 if raw_incoming_requests := payload.get("incomingRequests"): 2048 for incoming_request in raw_incoming_requests: 2049 incoming.append(self.deserialize_friend(incoming_request)) 2050 2051 if raw_outgoing_requests := payload.get("outgoingRequests"): 2052 for outgoing_request in raw_outgoing_requests: 2053 outgoing.append(self.deserialize_friend(outgoing_request)) 2054 2055 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2086 def deserialize_fireteams( 2087 self, payload: typedefs.JSONObject 2088 ) -> collections.Sequence[fireteams.Fireteam]: 2089 if "results" in payload: 2090 fireteams_ = [ 2091 self._set_fireteam_fields( 2092 elem, total_results=int(payload["totalResults"]) 2093 ) 2094 for elem in payload["results"] 2095 ] 2096 else: 2097 fireteams_ = [] 2098 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2100 def deserialize_fireteam_destiny_users( 2101 self, payload: typedefs.JSONObject 2102 ) -> fireteams.FireteamUser: 2103 destiny_obj = self.deserialize_destiny_membership(payload) 2104 return fireteams.FireteamUser( 2105 net=self._net, 2106 id=destiny_obj.id, 2107 code=destiny_obj.code, 2108 icon=destiny_obj.icon, 2109 types=destiny_obj.types, 2110 type=destiny_obj.type, 2111 is_public=destiny_obj.is_public, 2112 crossave_override=destiny_obj.crossave_override, 2113 name=destiny_obj.name, 2114 last_seen_name=destiny_obj.last_seen_name, 2115 fireteam_display_name=payload["FireteamDisplayName"], 2116 fireteam_membership_id=enums.MembershipType( 2117 payload["FireteamMembershipType"] 2118 ), 2119 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2121 def deserialize_fireteam_members( 2122 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2123 ) -> collections.Sequence[fireteams.FireteamMember]: 2124 members_: list[fireteams.FireteamMember] = [] 2125 if members := payload.get("Members" if not alternatives else "Alternates"): 2126 for member in members: 2127 bungie_fields = self.deserialize_partial_bungie_user(member) 2128 members_fields = fireteams.FireteamMember( 2129 destiny_user=self.deserialize_fireteam_destiny_users(member), 2130 has_microphone=member["hasMicrophone"], 2131 character_id=int(member["characterId"]), 2132 date_joined=time.clean_date(member["dateJoined"]), 2133 last_platform_invite_date=time.clean_date( 2134 member["lastPlatformInviteAttemptDate"] 2135 ), 2136 last_platform_invite_result=int( 2137 member["lastPlatformInviteAttemptResult"] 2138 ), 2139 net=self._net, 2140 name=bungie_fields.name, 2141 id=bungie_fields.id, 2142 icon=bungie_fields.icon, 2143 is_public=bungie_fields.is_public, 2144 crossave_override=bungie_fields.crossave_override, 2145 types=bungie_fields.types, 2146 type=bungie_fields.type, 2147 ) 2148 members_.append(members_fields) 2149 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
collections.Sequence[aiobungie.crates.FireteamUser]: A sequence of the fireteam members.
2151 def deserialize_available_fireteam( 2152 self, payload: typedefs.JSONObject 2153 ) -> fireteams.AvailableFireteam: 2154 fields = self._set_fireteam_fields(payload["Summary"]) 2155 return fireteams.AvailableFireteam( 2156 id=fields.id, 2157 group_id=fields.group_id, 2158 platform=fields.platform, 2159 activity_type=fields.activity_type, 2160 is_immediate=fields.is_immediate, 2161 is_public=fields.is_public, 2162 is_valid=fields.is_valid, 2163 owner_id=fields.owner_id, 2164 player_slot_count=fields.player_slot_count, 2165 available_player_slots=fields.available_player_slots, 2166 available_alternate_slots=fields.available_alternate_slots, 2167 title=fields.title, 2168 date_created=fields.date_created, 2169 locale=fields.locale, 2170 last_modified=fields.last_modified, 2171 total_results=fields.total_results, 2172 scheduled_time=fields.scheduled_time, 2173 date_modified=fields.date_modified, 2174 members=self.deserialize_fireteam_members(payload), 2175 alternatives=self.deserialize_fireteam_members(payload, alternatives=True), 2176 )
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
- An available fireteam object.
2178 def deserialize_available_fireteams( 2179 self, data: typedefs.JSONObject 2180 ) -> collections.Sequence[fireteams.AvailableFireteam]: 2181 if raw_results := data.get("results"): 2182 fireteam_results: list[fireteams.AvailableFireteam] = [ 2183 self.deserialize_available_fireteam(f) for f in raw_results 2184 ] 2185 else: 2186 fireteam_results = [] 2187 return fireteam_results
Deserialize a JSON payload sequence of fireteam objects.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]: A sequence of available fireteams.
2189 def deserialize_fireteam_party( 2190 self, payload: typedefs.JSONObject 2191 ) -> fireteams.FireteamParty: 2192 last_destination_hash: int | None = None 2193 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2194 last_destination_hash = int(raw_dest_hash) 2195 2196 return fireteams.FireteamParty( 2197 members=[ 2198 self._deserialize_fireteam_party_member(member) 2199 for member in payload["partyMembers"] 2200 ], 2201 activity=self._deserialize_fireteam_party_current_activity( 2202 payload["currentActivity"] 2203 ), 2204 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2205 last_destination_hash=last_destination_hash, 2206 tracking=payload["tracking"], 2207 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2250 def deserialize_seasonal_artifact( 2251 self, payload: typedefs.JSONObject 2252 ) -> season.Artifact: 2253 if raw_artifact := payload.get("seasonalArtifact"): 2254 if points := raw_artifact.get("pointProgression"): 2255 points_prog = progressions.Progression( 2256 hash=points["progressionHash"], 2257 level=points["level"], 2258 cap=points["levelCap"], 2259 daily_limit=points["dailyLimit"], 2260 weekly_limit=points["weeklyLimit"], 2261 current_progress=points["currentProgress"], 2262 daily_progress=points["dailyProgress"], 2263 needed=points["progressToNextLevel"], 2264 next_level=points["nextLevelAt"], 2265 ) 2266 2267 if bonus := raw_artifact.get("powerBonusProgression"): 2268 power_bonus_prog = progressions.Progression( 2269 hash=bonus["progressionHash"], 2270 level=bonus["level"], 2271 cap=bonus["levelCap"], 2272 daily_limit=bonus["dailyLimit"], 2273 weekly_limit=bonus["weeklyLimit"], 2274 current_progress=bonus["currentProgress"], 2275 daily_progress=bonus["dailyProgress"], 2276 needed=bonus["progressToNextLevel"], 2277 next_level=bonus["nextLevelAt"], 2278 ) 2279 artifact = season.Artifact( 2280 hash=raw_artifact["artifactHash"], 2281 power_bonus=raw_artifact["powerBonus"], 2282 acquired_points=raw_artifact["pointsAcquired"], 2283 bonus=power_bonus_prog, 2284 points=points_prog, 2285 ) 2286 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2288 def deserialize_profile_progression( 2289 self, payload: typedefs.JSONObject 2290 ) -> profile.ProfileProgression: 2291 return profile.ProfileProgression( 2292 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2293 checklist={ 2294 int(check_id): checklists 2295 for check_id, checklists in payload["data"]["checklists"].items() 2296 }, 2297 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2299 def deserialize_instanced_item( 2300 self, payload: typedefs.JSONObject 2301 ) -> items.ItemInstance: 2302 damage_type_hash: int | None = None 2303 if raw_damagetype_hash := payload.get("damageTypeHash"): 2304 damage_type_hash = int(raw_damagetype_hash) 2305 2306 required_hashes: typing.Optional[collections.Collection[int]] = None 2307 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2308 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2309 2310 breaker_type: items.ItemBreakerType | None = None 2311 if raw_break_type := payload.get("breakerType"): 2312 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2313 2314 breaker_type_hash: int | None = None 2315 if raw_break_type_hash := payload.get("breakerTypeHash"): 2316 breaker_type_hash = int(raw_break_type_hash) 2317 2318 energy: items.ItemEnergy | None = None 2319 if raw_energy := payload.get("energy"): 2320 energy = self.deserialize_item_energy(raw_energy) 2321 2322 primary_stats = None 2323 if raw_primary_stats := payload.get("primaryStat"): 2324 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2325 2326 return items.ItemInstance( 2327 damage_type=enums.DamageType(int(payload["damageType"])), 2328 damage_type_hash=damage_type_hash, 2329 primary_stat=primary_stats, 2330 item_level=int(payload["itemLevel"]), 2331 quality=int(payload["quality"]), 2332 is_equipped=payload["isEquipped"], 2333 can_equip=payload["canEquip"], 2334 equip_required_level=int(payload["equipRequiredLevel"]), 2335 required_equip_unlock_hashes=required_hashes, 2336 cant_equip_reason=int(payload["cannotEquipReason"]), 2337 breaker_type=breaker_type, 2338 breaker_type_hash=breaker_type_hash, 2339 energy=energy, 2340 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2342 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2343 energy_hash: int | None = None 2344 if raw_energy_hash := payload.get("energyTypeHash"): 2345 energy_hash = int(raw_energy_hash) 2346 2347 return items.ItemEnergy( 2348 hash=energy_hash, 2349 type=items.ItemEnergyType(int(payload["energyType"])), 2350 capacity=int(payload["energyCapacity"]), 2351 used_energy=int(payload["energyUsed"]), 2352 unused_energy=int(payload["energyUnused"]), 2353 )
2355 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2356 perk_hash: int | None = None 2357 if raw_perk_hash := payload.get("perkHash"): 2358 perk_hash = int(raw_perk_hash) 2359 2360 return items.ItemPerk( 2361 hash=perk_hash, 2362 icon=assets.Image(payload["iconPath"]), 2363 is_active=payload["isActive"], 2364 is_visible=payload["visible"], 2365 )
2367 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2368 plug_hash: int | None = None 2369 if raw_plug_hash := payload.get("plugHash"): 2370 plug_hash = int(raw_plug_hash) 2371 2372 enable_fail_indexes: list[int] | None = None 2373 if raw_indexes := payload.get("enableFailIndexes"): 2374 enable_fail_indexes = [int(index) for index in raw_indexes] 2375 2376 return items.ItemSocket( 2377 plug_hash=plug_hash, 2378 is_enabled=payload["isEnabled"], 2379 enable_fail_indexes=enable_fail_indexes, 2380 is_visible=payload.get("visible"), 2381 )
2390 def deserialize_plug_item_state( 2391 self, payload: typedefs.JSONObject 2392 ) -> items.PlugItemState: 2393 item_hash: int | None = None 2394 if raw_item_hash := payload.get("plugItemHash"): 2395 item_hash = int(raw_item_hash) 2396 2397 insert_fail_indexes: list[int] | None = None 2398 if raw_fail_indexes := payload.get("insertFailIndexes"): 2399 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2400 2401 enable_fail_indexes: list[int] | None = None 2402 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2403 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2404 2405 return items.PlugItemState( 2406 item_hash=item_hash, 2407 insert_fail_indexes=insert_fail_indexes, 2408 enable_fail_indexes=enable_fail_indexes, 2409 is_enabled=payload["enabled"], 2410 can_insert=payload["canInsert"], 2411 )
65@typing.final 66class FireteamActivity(int, enums.Enum): 67 """An enum for the fireteam activities.""" 68 69 ALL = 0 70 CRUCIBLE = 2 71 TRIALS_OF_OSIRIS = 3 72 NIGHTFALL = 4 73 ANY = 5 74 GAMBIT = 6 75 BLIND_WELL = 7 76 NIGHTMARE_HUNTS = 12 77 ALTARS_OF_SORROWS = 14 78 DUNGEON = 15 79 RAID_LW = 20 80 RAID_GOS = 21 81 RAID_DSC = 22 82 EXO_CHALLENGE = 23 83 S12_WRATHBORN = 24 84 EMPIRE_HUNTS = 25 85 S13_BATTLEGROUNDS = 26 86 EXOTIC_QUEST = 27 87 RAID_VOG = 28 88 S14_EXPUNGE = 30 89 S15_ASTRAL_ALIGNMENT = 31 90 S15_SHATTERED_RELAM = 32 91 SHATTERED_THRONE = 33 92 PROPHECY = 34 93 PIT_OF_HERESY = 35 94 DOE = 36 95 """Dares of Eternity.""" 96 DUNGEON_GOA = 37 97 """Grasp of Avarice.""" 98 VOW_OF_THE_DISCPILE = 38 99 CAMPAIGN = 39 100 WELLSPRING = 40 101 S16_BATTLEGROUNDS = 41 102 S17_NIGHTMARE_CONTAINMENT = 44 103 S17_SEVER = 45
An enum for the fireteam activities.
129@typing.final 130class FireteamDate(int, enums.Enum): 131 """An enum for fireteam date ranges.""" 132 133 ALL = 0 134 NOW = 1 135 TODAY = 2 136 TWO_DAYS = 3 137 THIS_WEEK = 4
An enum for fireteam date ranges.
106@typing.final 107class FireteamLanguage(str, enums.Enum): 108 """An enum for fireteams languages filters.""" 109 110 ALL = "" 111 ENGLISH = "en" 112 FRENCH = "fr" 113 ESPANOL = "es" 114 DEUTSCH = "de" 115 ITALIAN = "it" 116 JAPANESE = "ja" 117 PORTUGUESE = "pt-br" 118 RUSSIAN = "ru" 119 POLISH = "pl" 120 KOREAN = "ko" 121 # ? China 122 ZH_CHT = "zh-cht" 123 ZH_CHS = "zh-chs" 124 125 def __str__(self) -> str: 126 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
52@typing.final 53class FireteamPlatform(int, enums.Enum): 54 """An enum for fireteam related to bungie fireteams. 55 This is different from the normal `aiobungie.MembershipType`. 56 """ 57 58 ANY = 0 59 PSN_NETWORK = 1 60 XBOX_LIVE = 2 61 STEAM = 4 62 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
90class Flag(__enum.Flag): 91 """Builtin Python enum flag with extra handlings.""" 92 93 # Needs to type this here for mypy 94 _value_: int 95 96 @property 97 def name(self) -> str: # type: ignore[override] 98 if self._name_ is None: 99 self._name_ = f"UNKNOWN {self._value_}" 100 101 return self._name_ 102 103 @property 104 def value(self) -> int: # type: ignore[override] 105 return self._value_ 106 107 def __str__(self) -> str: 108 return self.name 109 110 def __repr__(self) -> str: 111 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 112 113 def __int__(self) -> int: 114 return int(self.value) 115 116 def __or__(self, other: Flag | int) -> Flag: 117 return self.__class__(self._value_ | int(other)) 118 119 def __xor__(self, other: Flag | int) -> Flag: 120 return self.__class__(self._value_ ^ int(other)) 121 122 def __and__(self, other: Flag | int) -> Flag: 123 return self.__class__(other & int(other)) 124 125 def __invert__(self) -> Flag: 126 return self.__class__(~self._value_) 127 128 def __contains__(self, other: Flag | int) -> bool: 129 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
137@attrs.define(auto_exc=True) 138class Forbidden(HTTPException): 139 """Exception that's raised for when status code 403 occurs.""" 140 141 http_status: http.HTTPStatus = attrs.field( 142 default=http.HTTPStatus.FORBIDDEN, init=False 143 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
258@typing.final 259class GameMode(int, Enum): 260 """An Enum for all available gamemodes in Destiny 2.""" 261 262 NONE = 0 263 STORY = 2 264 STRIKE = 3 265 RAID = 4 266 ALLPVP = 5 267 PATROL = 6 268 ALLPVE = 7 269 RESERVED9 = 9 270 CONTROL = 10 271 RESERVED11 = 11 272 CLASH = 12 273 RESERVED13 = 13 274 CRIMSONDOUBLES = 15 275 NIGHTFALL = 16 276 HEROICNIGHTFALL = 17 277 ALLSTRIKES = 18 278 IRONBANNER = 19 279 RESERVED20 = 20 280 RESERVED21 = 21 281 RESERVED22 = 22 282 RESERVED24 = 24 283 ALLMAYHEM = 25 284 RESERVED26 = 26 285 RESERVED27 = 27 286 RESERVED28 = 28 287 RESERVED29 = 29 288 RESERVED30 = 30 289 SUPREMACY = 31 290 PRIVATEMATCHESALL = 32 291 SURVIVAL = 37 292 COUNTDOWN = 38 293 TRIALSOFTHENINE = 39 294 SOCIAL = 40 295 TRIALSCOUNTDOWN = 41 296 TRIALSSURVIVAL = 42 297 IRONBANNERCONTROL = 43 298 IRONBANNERCLASH = 44 299 IRONBANNERSUPREMACY = 45 300 SCOREDNIGHTFALL = 46 301 SCOREDHEROICNIGHTFALL = 47 302 RUMBLE = 48 303 ALLDOUBLES = 49 304 DOUBLES = 50 305 PRIVATEMATCHESCLASH = 51 306 PRIVATEMATCHESCONTROL = 52 307 PRIVATEMATCHESSUPREMACY = 53 308 PRIVATEMATCHESCOUNTDOWN = 54 309 PRIVATEMATCHESSURVIVAL = 55 310 PRIVATEMATCHESMAYHEM = 56 311 PRIVATEMATCHESRUMBLE = 57 312 HEROICADVENTURE = 58 313 SHOWDOWN = 59 314 LOCKDOWN = 60 315 SCORCHED = 61 316 SCORCHEDTEAM = 62 317 GAMBIT = 63 318 ALLPVECOMPETITIVE = 64 319 BREAKTHROUGH = 65 320 BLACKARMORYRUN = 66 321 SALVAGE = 67 322 IRONBANNERSALVAGE = 68 323 PVPCOMPETITIVE = 69 324 PVPQUICKPLAY = 70 325 CLASHQUICKPLAY = 71 326 CLASHCOMPETITIVE = 72 327 CONTROLQUICKPLAY = 73 328 CONTROLCOMPETITIVE = 74 329 GAMBITPRIME = 75 330 RECKONING = 76 331 MENAGERIE = 77 332 VEXOFFENSIVE = 78 333 NIGHTMAREHUNT = 79 334 ELIMINATION = 80 335 MOMENTUM = 81 336 DUNGEON = 82 337 SUNDIAL = 83 338 TRIALS_OF_OSIRIS = 84 339 DARES = 85 340 OFFENSIVE = 86 341 LOSTSECTOR = 87 342 RIFT = 88 343 ZONECONTROL = 89 344 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
57@typing.final 58class GatingScope(int, enums.Enum): 59 """An enum represents restrictive type of gating that is being performed by an entity. 60 61 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 62 applies to everyone equally, or to their specific Profile or Character states. 63 """ 64 65 NONE = 0 66 GLOBAL = 1 67 CLAN = 2 68 PROFILE = 3 69 CHARACTER = 4 70 ITEM = 5 71 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
475@typing.final 476class Gender(int, Enum): 477 """An Enum for Destiny Genders.""" 478 479 MALE = 0 480 FEMALE = 1 481 UNKNOWN = 2
An Enum for Destiny Genders.
644@typing.final 645class GroupType(int, Enum): 646 """An enums for the known bungie group types.""" 647 648 GENERAL = 0 649 CLAN = 1
An enums for the known bungie group types.
79@attrs.define(auto_exc=True) 80class HTTPError(AiobungieError): 81 """Base HTTP request errors exception.""" 82 83 message: str 84 """The error message.""" 85 86 http_status: http.HTTPStatus 87 """The response status."""
Base HTTP request errors exception.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
90@attrs.define(auto_exc=True, kw_only=True) 91class HTTPException(HTTPError): 92 """An in-depth HTTP exception that's raised with more information.""" 93 94 error_code: int 95 """The returned Bungie error status code.""" 96 97 http_status: http.HTTPStatus 98 """The request response http status.""" 99 100 throttle_seconds: int 101 """The Bungie response throttle seconds.""" 102 103 url: typedefs.StrOrURL | None 104 """The URL/endpoint caused this error.""" 105 106 body: typing.Any 107 """The response body.""" 108 109 headers: multidict.CIMultiDictProxy[str] 110 """The response headers.""" 111 112 message: str 113 """A Bungie human readable message describes the cause of the error.""" 114 115 error_status: str 116 """A Bungie short error status describes the cause of the error.""" 117 118 message_data: dict[str, str] 119 """A dict of string key, value that includes each cause of the error 120 to a message describes information about that error. 121 """ 122 123 def __str__(self) -> str: 124 if self.message: 125 message_body = self.message 126 127 if self.error_status: 128 error_status_body = self.error_status 129 130 return ( 131 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 132 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 133 f"{str(self.body)}" 134 )
An in-depth HTTP exception that's raised with more information.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
73class Image: 74 """Representation of an image/avatar/picture at Bungie. 75 76 Example 77 ------- 78 ```py 79 from aiobungie import Image 80 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 81 print(img) 82 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 83 84 # Stream the image. 85 async for chunk in img: 86 # Byte chunks of the image. 87 print(chunk) 88 89 # Save the image to a file. 90 await img.save("file_name", "/my/path/to/save/to", "jpeg") 91 ``` 92 93 Parameters 94 ---------- 95 path : `str | None` 96 The path to the image.. 97 """ 98 99 __slots__ = ("_path",) 100 101 def __init__(self, path: str) -> None: 102 self._path = path 103 104 @property 105 def is_missing(self) -> bool: 106 return not self._path 107 108 @property 109 def url(self) -> str: 110 """The URL to the image.""" 111 return self.create_url() 112 113 @staticmethod 114 def default() -> str: 115 """Returns the path to the missing Bungie image. 116 117 Note 118 ---- 119 This returns the path only, If you want an actual image object use `Image.default_or_else()` 120 """ 121 return "/img/misc/missing_icon_d2.png" 122 123 @classmethod 124 def default_or_else(cls, path: str | None = None) -> Self: 125 """Return the default image if `path` was `None` otherwise an `Image` object. 126 127 Example 128 ------- 129 ```py 130 img = Image.default_or_else(None) 131 print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png 132 133 img = Image.default_or_else("/some_path/image.png") 134 ``` 135 """ 136 return cls(path or Image.default()) 137 138 def create_url(self) -> str: 139 """Creates a full URL to the image path. 140 141 Returns 142 ------- 143 str 144 The URL to the image. 145 """ 146 return f"{url.BASE}/{self._path if self._path else self.default()}" 147 148 async def save( 149 self, 150 file_name: str, 151 path: pathlib.Path | str, 152 /, 153 mime_type: MimeType | str = MimeType.JPEG, 154 ) -> None: 155 """Saves the image to a file. 156 157 Parameters 158 ---------- 159 file_name : `str` 160 A name for the file to save the image to. 161 path : `pathlib.Path | str` 162 A path tp save the image to. 163 164 Other Parameters 165 ---------------- 166 mime_type : `MimeType | str` 167 MIME type of the image. Defaults to JPEG. 168 169 Raises 170 ------ 171 `FileNotFoundError` 172 If the path provided does not exist. 173 `RuntimeError` 174 If the image could not be saved. 175 `PermissionError` 176 If the path provided is not writable or does not have write permissions. 177 """ 178 if isinstance(path, pathlib.Path) and not path.exists(): 179 raise FileNotFoundError(f"File does not exist: {path!r}") 180 181 if self.is_missing: 182 return 183 184 path = pathlib.Path(path) 185 186 loop = helpers.get_or_make_loop() 187 pool = concurrent.futures.ThreadPoolExecutor() 188 189 try: 190 with pool: 191 await loop.run_in_executor( 192 pool, _write, path, file_name, mime_type, await self.read() 193 ) 194 _LOGGER.info("Saved image to %s", file_name) 195 196 except asyncio.CancelledError: 197 pass 198 199 except Exception as err: 200 raise RuntimeError("Encountered an error while saving image.") from err 201 202 async def read(self) -> bytes: 203 """Read this image bytes. 204 205 Returns 206 ------- 207 `bytes` 208 The bytes of this image. 209 """ 210 client_session = aiohttp.ClientSession() 211 212 try: 213 await client_session.__aenter__() 214 response = await client_session.get(self.create_url()) 215 216 if 300 >= response.status >= 200: 217 reader = await response.read() 218 219 except Exception as exc: 220 raise RuntimeError(f"Failed to read image: {exc}") from None 221 finally: 222 await client_session.__aexit__(None, None, None) 223 return reader 224 225 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 226 """Iterates over the image bytes lazily. 227 228 Example 229 ------- 230 import aiobungie 231 232 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 233 async for chunk in resource.iter(): 234 print(chunk) 235 236 Returns 237 ------- 238 `collections.AsyncGenerator[bytes, None]` 239 An async generator of the image bytes. 240 """ 241 242 async for chunk in self: 243 yield chunk 244 245 def __eq__(self, __value: object) -> bool: 246 if not isinstance(__value, Image): 247 return NotImplemented 248 return self._path == __value._path 249 250 def __ne__(self, __value: object) -> bool: 251 return not self.__eq__(__value) 252 253 def __repr__(self) -> str: 254 return f"Image(url={self.create_url()})" 255 256 def __str__(self) -> str: 257 return self.create_url() 258 259 def __aiter__(self) -> Image: 260 return self 261 262 async def __anext__(self) -> bytes: 263 return await self.read() 264 265 def __await__(self) -> collections.Generator[None, None, bytes]: 266 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image..
113 @staticmethod 114 def default() -> str: 115 """Returns the path to the missing Bungie image. 116 117 Note 118 ---- 119 This returns the path only, If you want an actual image object use `Image.default_or_else()` 120 """ 121 return "/img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
Note
This returns the path only, If you want an actual image object use Image.default_or_else()
123 @classmethod 124 def default_or_else(cls, path: str | None = None) -> Self: 125 """Return the default image if `path` was `None` otherwise an `Image` object. 126 127 Example 128 ------- 129 ```py 130 img = Image.default_or_else(None) 131 print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png 132 133 img = Image.default_or_else("/some_path/image.png") 134 ``` 135 """ 136 return cls(path or Image.default())
Return the default image if path was None otherwise an Image object.
Example
img = Image.default_or_else(None)
print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png
img = Image.default_or_else("/some_path/image.png")
138 def create_url(self) -> str: 139 """Creates a full URL to the image path. 140 141 Returns 142 ------- 143 str 144 The URL to the image. 145 """ 146 return f"{url.BASE}/{self._path if self._path else self.default()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
148 async def save( 149 self, 150 file_name: str, 151 path: pathlib.Path | str, 152 /, 153 mime_type: MimeType | str = MimeType.JPEG, 154 ) -> None: 155 """Saves the image to a file. 156 157 Parameters 158 ---------- 159 file_name : `str` 160 A name for the file to save the image to. 161 path : `pathlib.Path | str` 162 A path tp save the image to. 163 164 Other Parameters 165 ---------------- 166 mime_type : `MimeType | str` 167 MIME type of the image. Defaults to JPEG. 168 169 Raises 170 ------ 171 `FileNotFoundError` 172 If the path provided does not exist. 173 `RuntimeError` 174 If the image could not be saved. 175 `PermissionError` 176 If the path provided is not writable or does not have write permissions. 177 """ 178 if isinstance(path, pathlib.Path) and not path.exists(): 179 raise FileNotFoundError(f"File does not exist: {path!r}") 180 181 if self.is_missing: 182 return 183 184 path = pathlib.Path(path) 185 186 loop = helpers.get_or_make_loop() 187 pool = concurrent.futures.ThreadPoolExecutor() 188 189 try: 190 with pool: 191 await loop.run_in_executor( 192 pool, _write, path, file_name, mime_type, await self.read() 193 ) 194 _LOGGER.info("Saved image to %s", file_name) 195 196 except asyncio.CancelledError: 197 pass 198 199 except Exception as err: 200 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): MIME type of the image. Defaults to JPEG.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
202 async def read(self) -> bytes: 203 """Read this image bytes. 204 205 Returns 206 ------- 207 `bytes` 208 The bytes of this image. 209 """ 210 client_session = aiohttp.ClientSession() 211 212 try: 213 await client_session.__aenter__() 214 response = await client_session.get(self.create_url()) 215 216 if 300 >= response.status >= 200: 217 reader = await response.read() 218 219 except Exception as exc: 220 raise RuntimeError(f"Failed to read image: {exc}") from None 221 finally: 222 await client_session.__aexit__(None, None, None) 223 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
225 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 226 """Iterates over the image bytes lazily. 227 228 Example 229 ------- 230 import aiobungie 231 232 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 233 async for chunk in resource.iter(): 234 print(chunk) 235 236 Returns 237 ------- 238 `collections.AsyncGenerator[bytes, None]` 239 An async generator of the image bytes. 240 """ 241 242 async for chunk in self: 243 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
241@attrs.define(auto_exc=True) 242class InternalServerError(HTTPException): 243 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
710@typing.final 711class ItemBindStatus(int, Enum): 712 """An enum for Destiny 2 items bind status.""" 713 714 NOT_BOUND = 0 715 BOUND_TO_CHARACTER = 1 716 BOUND_TO_ACCOUNT = 2 717 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
720@typing.final 721class ItemLocation(int, Enum): 722 """An enum for Destiny 2 items location.""" 723 724 UNKNOWN = 0 725 INVENTORY = 1 726 VAULT = 2 727 VENDOR = 3 728 POSTMASTER = 4
An enum for Destiny 2 items location.
745@typing.final 746class ItemState(Flag): 747 """An enum for Destiny 2 item states.""" 748 749 NONE = 0 750 LOCKED = 1 << 0 751 TRACKED = 1 << 1 752 MASTERWORKED = 1 << 2 753 CRAFTED = 1 << 3 754 """If this bit is set, the item has been 'crafted' by the player.""" 755 HIGHLITED_OBJECTIVE = 1 << 4 756 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
577@typing.final 578class ItemSubType(int, Enum): 579 """An enum for Destiny 2 inventory items subtype.""" 580 581 NONE = 0 582 AUTORIFLE = 6 583 SHOTGUN = 7 584 MACHINEGUN = 8 585 HANDCANNON = 9 586 ROCKETLAUNCHER = 10 587 FUSIONRIFLE = 11 588 SNIPERRIFLE = 12 589 PULSERIFLE = 13 590 SCOUTRIFLE = 14 591 SIDEARM = 17 592 SWORD = 18 593 MASK = 19 594 SHADER = 20 595 ORNAMENT = 21 596 FUSIONRIFLELINE = 22 597 GRENADELAUNCHER = 23 598 SUBMACHINEGUN = 24 599 TRACERIFLE = 25 600 HELMETARMOR = 26 601 GAUNTLETSARMOR = 27 602 CHESTARMOR = 28 603 LEGARMOR = 29 604 CLASSARMOR = 30 605 BOW = 31 606 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
609@typing.final 610class ItemTier(int, Enum): 611 """An enum for a Destiny 2 item tier.""" 612 613 NONE = 0 614 BASIC = 3340296461 615 COMMON = 2395677314 616 RARE = 2127292149 617 LEGENDERY = 4008398120 618 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
544@typing.final 545class ItemType(int, Enum): 546 """Enums for Destiny2's item types.""" 547 548 NONE = 0 549 CURRENCY = 1 550 ARMOR = 2 551 WEAPON = 3 552 MESSAGE = 7 553 ENGRAM = 8 554 CONSUMABLE = 9 555 EXCHANGEMATERIAL = 10 556 MISSIONREWARD = 11 557 QUESTSTEP = 12 558 QUESTSTEPCOMPLETE = 13 559 EMBLEM = 14 560 QUEST = 15 561 SUBCLASS = 16 562 CLANBANNER = 17 563 AURA = 18 564 MOD = 19 565 DUMMY = 20 566 SHIP = 21 567 VEHICLE = 22 568 EMOTE = 23 569 GHOST = 24 570 PACKAGE = 25 571 BOUNTY = 26 572 WRAPPER = 27 573 SEASONALARTIFACT = 28 574 FINISHER = 29
Enums for Destiny2's item types.
47class Iterator(typing.Generic[Item], collections.Iterator[Item]): 48 """A Flat, In-Memory iterator for sequenced based data. 49 50 Example 51 ------- 52 ```py 53 iterator = Iterator([1, 2, 3]) 54 55 # Map the results. 56 for item in iterator.map(lambda item: item * 2): 57 print(item) 58 # 2 59 # 4 60 61 # Indexing is also supported. 62 print(iterator[0]) 63 # 1 64 65 # Normal iteration. 66 for item in iterator: 67 print(item) 68 # 1 69 # 2 70 # 3 71 72 # Union two iterators. 73 iterator2 = Iterator([4, 5, 6]) 74 final = iterator | iterator2 75 # <Iterator([1, 2, 3, 4, 5, 6])> 76 ``` 77 78 Parameters 79 ---------- 80 items: `collections.Iterable[Item]` 81 The items to iterate over. 82 """ 83 84 __slots__ = ("_items",) 85 86 def __init__(self, items: collections.Iterable[Item]) -> None: 87 self._items = _builtins.iter(items) 88 89 @typing.overload 90 def collect(self) -> list[Item]: 91 ... 92 93 @typing.overload 94 def collect(self, casting: _B) -> list[_B]: 95 ... 96 97 def collect(self, casting: _B | None = None) -> list[Item] | list[_B]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = Iterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items) 120 121 def copied(self) -> Iterator[Item]: 122 """Creates an iterator which `deeply` copies all of its elements. 123 124 Example 125 ------- 126 ```py 127 it = Iterator([None, None, None]) 128 copied_iter = it.copied() 129 assert it.collect() == copied.collect() 130 ``` 131 """ 132 return Iterator(_copy.deepcopy(self._items)) 133 134 def next(self) -> Item: 135 """Returns the next item in the iterator. 136 137 Example 138 ------- 139 ```py 140 iterator = Iterator(["1", "2", "3"]) 141 item = iterator.next() 142 assert item == "1" 143 item = iterator.next() 144 assert item == "2" 145 ``` 146 147 Raises 148 ------ 149 `StopIteration` 150 If no elements are left in the iterator. 151 """ 152 try: 153 return self.__next__() 154 except StopIteration: 155 self._ok() 156 157 def map( 158 self, predicate: collections.Callable[[Item], OtherItem] 159 ) -> Iterator[OtherItem]: 160 """Maps each item in the iterator to its predicated value. 161 162 Example 163 ------- 164 ```py 165 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 166 print(iterator) 167 # <Iterator([1, 2, 3])> 168 ``` 169 170 Parameters 171 ---------- 172 predicate: `collections.Callable[[Item], OtherItem]` 173 The function to map each item in the iterator to its predicated value. 174 175 Returns 176 ------- 177 `Iterator[OtherItem]` 178 The mapped iterator. 179 180 Raises 181 ------ 182 `StopIteration` 183 If no elements are left in the iterator. 184 """ 185 return Iterator(map(predicate, self._items)) 186 187 def take(self, n: int) -> Iterator[Item]: 188 """Take the first number of items until the number of items are yielded or 189 the end of the iterator is reached. 190 191 Example 192 ------- 193 ```py 194 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 195 print(iterator.take(2)) 196 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 197 ``` 198 199 Parameters 200 ---------- 201 n: `int` 202 The number of items to take. 203 204 Raises 205 ------ 206 `StopIteration` 207 If no elements are left in the iterator. 208 """ 209 return Iterator(itertools.islice(self._items, n)) 210 211 def take_while( 212 self, predicate: collections.Callable[[Item], bool] 213 ) -> Iterator[Item]: 214 """Yields items from the iterator while predicate returns `True`. 215 216 Example 217 ------- 218 ```py 219 iterator = Iterator([STEAM, XBOX, STADIA]) 220 print(iterator.take_while(lambda platform: platform is not XBOX)) 221 # <Iterator([STEAM])> 222 ``` 223 224 Parameters 225 ---------- 226 predicate: `collections.Callable[[Item], bool]` 227 The function to predicate each item in the iterator. 228 229 Raises 230 ------ 231 `StopIteration` 232 If no elements are left in the iterator. 233 """ 234 return Iterator(itertools.takewhile(predicate, self._items)) 235 236 def drop_while( 237 self, predicate: collections.Callable[[Item], bool] 238 ) -> Iterator[Item]: 239 """Yields items from the iterator while predicate returns `False`. 240 241 Example 242 ------- 243 ```py 244 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 245 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 246 # <Iterator([DestinyMembership(name="Bob")])> 247 ``` 248 249 Parameters 250 ---------- 251 predicate: `collections.Callable[[Item], bool]` 252 The function to predicate each item in the iterator. 253 254 Raises 255 ------ 256 `StopIteration` 257 If no elements are left in the iterator. 258 """ 259 return Iterator(itertools.dropwhile(predicate, self._items)) 260 261 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 262 """Filters the iterator to only yield items that match the predicate. 263 264 Example 265 ------- 266 ```py 267 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 268 print(names.filter(lambda n: n != "Jim")) 269 # <Iterator(["Bob", "Mike", "Jess"])> 270 ``` 271 """ 272 return Iterator(filter(predicate, self._items)) 273 274 def skip(self, n: int) -> Iterator[Item]: 275 """Skips the first number of items in the iterator. 276 277 Example 278 ------- 279 ```py 280 iterator = Iterator([STEAM, XBOX, STADIA]) 281 print(iterator.skip(1)) 282 # <Iterator([XBOX, STADIA])> 283 ``` 284 """ 285 return Iterator(itertools.islice(self._items, n, None)) 286 287 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 288 """Zips the iterator with another iterable. 289 290 Example 291 ------- 292 ```py 293 iterator = Iterator([1, 3, 5]) 294 other = Iterator([2, 4, 6]) 295 for item, other_item in iterator.zip(other): 296 print(item, other_item) 297 # <Iterator([(1, 2), (3, 4), (5, 6)])> 298 ``` 299 300 Parameters 301 ---------- 302 other: `Iterator[OtherItem]` 303 The iterable to zip with. 304 305 Raises 306 ------ 307 `StopIteration` 308 If no elements are left in the iterator. 309 """ 310 return Iterator(zip(self._items, other)) 311 312 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 313 """`True` if all items in the iterator match the predicate. 314 315 Example 316 ------- 317 ```py 318 iterator = Iterator([1, 2, 3]) 319 while iterator.all(lambda item: isinstance(item, int)): 320 print("Still all integers") 321 continue 322 # Still all integers 323 ``` 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return all(predicate(item) for item in self) 336 337 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 338 """`True` if any items in the iterator match the predicate. 339 340 Example 341 ------- 342 ```py 343 iterator = Iterator([1, 2, 3]) 344 if iterator.any(lambda item: isinstance(item, int)): 345 print("At least one item is an int.") 346 # At least one item is an int. 347 ``` 348 349 Parameters 350 ---------- 351 predicate: `collections.Callable[[Item], bool]` 352 The function to test each item in the iterator. 353 354 Raises 355 ------ 356 `StopIteration` 357 If no elements are left in the iterator. 358 """ 359 return any(predicate(item) for item in self) 360 361 def sort( 362 self, 363 *, 364 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 365 reverse: bool = False, 366 ) -> Iterator[Item]: 367 """Sorts the iterator. 368 369 Example 370 ------- 371 ```py 372 iterator = Iterator([3, 1, 6, 7]) 373 print(iterator.sort(key=lambda item: item)) 374 # <Iterator([1, 3, 6, 7])> 375 ``` 376 377 Parameters 378 ---------- 379 key: `collections.Callable[[Item], Any]` 380 The function to sort by. 381 reverse: `bool` 382 Whether to reverse the sort. 383 384 Raises 385 ------ 386 `StopIteration` 387 If no elements are left in the iterator. 388 """ 389 return Iterator(sorted(self._items, key=key, reverse=reverse)) 390 391 def first(self) -> Item: 392 """Returns the first item in the iterator. 393 394 Example 395 ------- 396 ```py 397 iterator = Iterator([3, 1, 6, 7]) 398 print(iterator.first()) 399 3 400 ``` 401 402 Raises 403 ------ 404 `StopIteration` 405 If no elements are left in the iterator. 406 """ 407 return self.take(1).next() 408 409 def last(self) -> Item: 410 """Returns the last item in the iterator. 411 412 Example 413 ------ 414 ```py 415 it = Iterator((1, 2, 3)) 416 assert it.first() == 1 and it.last() == 3 417 ``` 418 """ 419 return self.reversed().first() 420 421 def reversed(self) -> Iterator[Item]: 422 """Returns a new iterator that yields the items in the iterator in reverse order. 423 424 Example 425 ------- 426 ```py 427 iterator = Iterator([3, 1, 6, 7]) 428 print(iterator.reversed()) 429 # <Iterator([7, 6, 1, 3])> 430 ``` 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return Iterator(reversed(self.collect())) 438 439 def count(self) -> int: 440 """Returns the number of items in the iterator. 441 442 Example 443 ------- 444 ```py 445 iterator = Iterator([3, 1, 6, 7]) 446 print(iterator.count()) 447 4 448 ``` 449 """ 450 count = 0 451 for _ in self: 452 count += 1 453 454 return count 455 456 def union(self, other: Iterator[Item]) -> Iterator[Item]: 457 """Returns a new iterator that yields all items from both iterators. 458 459 Example 460 ------- 461 ```py 462 iterator = Iterator([1, 2, 3]) 463 other = Iterator([4, 5, 6]) 464 print(iterator.union(other)) 465 # <Iterator([1, 2, 3, 4, 5, 6])> 466 ``` 467 468 Parameters 469 ---------- 470 other: `Iterator[Item]` 471 The iterable to union with. 472 473 Raises 474 ------ 475 `StopIteration` 476 If no elements are left in the iterator. 477 """ 478 return Iterator(itertools.chain(self._items, other)) 479 480 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 481 """Calls the function on each item in the iterator. 482 483 Example 484 ------- 485 ```py 486 iterator = Iterator([1, 2, 3]) 487 iterator.for_each(lambda item: print(item)) 488 # 1 489 # 2 490 # 3 491 ``` 492 493 Parameters 494 ---------- 495 func: `typeshed.Callable[[Item], None]` 496 The function to call on each item in the iterator. 497 """ 498 for item in self: 499 func(item) 500 501 async def async_for_each( 502 self, 503 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 504 ) -> None: 505 """Calls the async function on each item in the iterator concurrently. 506 507 Example 508 ------- 509 ```py 510 async def signup(username: str) -> None: 511 async with aiohttp.request('POST', '...') as r: 512 # Actual logic. 513 ... 514 515 async def main(): 516 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 517 await users.async_for_each(lambda username: signup(username)) 518 ``` 519 520 Parameters 521 ---------- 522 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 523 The async function to call on each item in the iterator. 524 """ 525 await _helpers.awaits(*(func(item) for item in self)) 526 527 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 528 """Returns a new iterator that yields tuples of the index and item. 529 530 Example 531 ------- 532 ```py 533 iterator = Iterator([1, 2, 3]) 534 for index, item in iterator.enumerate(): 535 print(index, item) 536 # 0 1 537 # 1 2 538 # 2 3 539 ``` 540 541 Raises 542 ------ 543 `StopIteration` 544 If no elements are left in the iterator. 545 """ 546 return Iterator(enumerate(self._items, start=start)) 547 548 def _ok(self) -> typing.NoReturn: 549 raise StopIteration("No more items in the iterator.") from None 550 551 def __getitem__(self, index: int) -> Item: 552 try: 553 return self.skip(index).first() 554 except IndexError: 555 self._ok() 556 557 def __or__(self, other: Iterator[Item]) -> Iterator[Item]: 558 return self.union(other) 559 560 # This is a never. 561 def __setitem__(self) -> typing.NoReturn: 562 raise TypeError( 563 f"{type(self).__name__} doesn't support item assignment." 564 ) from None 565 566 def __repr__(self) -> str: 567 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 568 569 def __len__(self) -> int: 570 return self.count() 571 572 def __iter__(self) -> Iterator[Item]: 573 return self 574 575 def __next__(self) -> Item: 576 try: 577 item = next(self._items) 578 except StopIteration: 579 self._ok() 580 581 return item
A Flat, In-Memory iterator for sequenced based data.
Example
iterator = Iterator([1, 2, 3])
# Map the results.
for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# Indexing is also supported.
print(iterator[0])
# 1
# Normal iteration.
for item in iterator:
print(item)
# 1
# 2
# 3
# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
97 def collect(self, casting: _B | None = None) -> list[Item] | list[_B]: 98 """Collects all items in the iterator into a list and cast them into an object if provided. 99 100 Example 101 ------- 102 >>> iterator = Iterator([1, 2, 3]) 103 >>> iterator.collect(casting=str) 104 ["1", "2", "3"] 105 106 Parameters 107 ---------- 108 casting: `T | None` 109 The type to cast the items to. If `None` is provided, the items will be returned as is. 110 111 Raises 112 ------ 113 `StopIteration` 114 If no elements are left in the iterator. 115 """ 116 if casting is not None: 117 return typing.cast(list[_B], list(map(casting, self._items))) 118 119 return list(self._items)
Collects all items in the iterator into a list and cast them into an object if provided.
Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
- casting (
T | None): The type to cast the items to. IfNoneis provided, the items will be returned as is.
Raises
StopIteration: If no elements are left in the iterator.
121 def copied(self) -> Iterator[Item]: 122 """Creates an iterator which `deeply` copies all of its elements. 123 124 Example 125 ------- 126 ```py 127 it = Iterator([None, None, None]) 128 copied_iter = it.copied() 129 assert it.collect() == copied.collect() 130 ``` 131 """ 132 return Iterator(_copy.deepcopy(self._items))
Creates an iterator which deeply copies all of its elements.
Example
it = Iterator([None, None, None])
copied_iter = it.copied()
assert it.collect() == copied.collect()
134 def next(self) -> Item: 135 """Returns the next item in the iterator. 136 137 Example 138 ------- 139 ```py 140 iterator = Iterator(["1", "2", "3"]) 141 item = iterator.next() 142 assert item == "1" 143 item = iterator.next() 144 assert item == "2" 145 ``` 146 147 Raises 148 ------ 149 `StopIteration` 150 If no elements are left in the iterator. 151 """ 152 try: 153 return self.__next__() 154 except StopIteration: 155 self._ok()
Returns the next item in the iterator.
Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
157 def map( 158 self, predicate: collections.Callable[[Item], OtherItem] 159 ) -> Iterator[OtherItem]: 160 """Maps each item in the iterator to its predicated value. 161 162 Example 163 ------- 164 ```py 165 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 166 print(iterator) 167 # <Iterator([1, 2, 3])> 168 ``` 169 170 Parameters 171 ---------- 172 predicate: `collections.Callable[[Item], OtherItem]` 173 The function to map each item in the iterator to its predicated value. 174 175 Returns 176 ------- 177 `Iterator[OtherItem]` 178 The mapped iterator. 179 180 Raises 181 ------ 182 `StopIteration` 183 If no elements are left in the iterator. 184 """ 185 return Iterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
- predicate (
collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
Iterator[OtherItem]: The mapped iterator.
Raises
StopIteration: If no elements are left in the iterator.
187 def take(self, n: int) -> Iterator[Item]: 188 """Take the first number of items until the number of items are yielded or 189 the end of the iterator is reached. 190 191 Example 192 ------- 193 ```py 194 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 195 print(iterator.take(2)) 196 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 197 ``` 198 199 Parameters 200 ---------- 201 n: `int` 202 The number of items to take. 203 204 Raises 205 ------ 206 `StopIteration` 207 If no elements are left in the iterator. 208 """ 209 return Iterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
211 def take_while( 212 self, predicate: collections.Callable[[Item], bool] 213 ) -> Iterator[Item]: 214 """Yields items from the iterator while predicate returns `True`. 215 216 Example 217 ------- 218 ```py 219 iterator = Iterator([STEAM, XBOX, STADIA]) 220 print(iterator.take_while(lambda platform: platform is not XBOX)) 221 # <Iterator([STEAM])> 222 ``` 223 224 Parameters 225 ---------- 226 predicate: `collections.Callable[[Item], bool]` 227 The function to predicate each item in the iterator. 228 229 Raises 230 ------ 231 `StopIteration` 232 If no elements are left in the iterator. 233 """ 234 return Iterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
236 def drop_while( 237 self, predicate: collections.Callable[[Item], bool] 238 ) -> Iterator[Item]: 239 """Yields items from the iterator while predicate returns `False`. 240 241 Example 242 ------- 243 ```py 244 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 245 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 246 # <Iterator([DestinyMembership(name="Bob")])> 247 ``` 248 249 Parameters 250 ---------- 251 predicate: `collections.Callable[[Item], bool]` 252 The function to predicate each item in the iterator. 253 254 Raises 255 ------ 256 `StopIteration` 257 If no elements are left in the iterator. 258 """ 259 return Iterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
261 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 262 """Filters the iterator to only yield items that match the predicate. 263 264 Example 265 ------- 266 ```py 267 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 268 print(names.filter(lambda n: n != "Jim")) 269 # <Iterator(["Bob", "Mike", "Jess"])> 270 ``` 271 """ 272 return Iterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
274 def skip(self, n: int) -> Iterator[Item]: 275 """Skips the first number of items in the iterator. 276 277 Example 278 ------- 279 ```py 280 iterator = Iterator([STEAM, XBOX, STADIA]) 281 print(iterator.skip(1)) 282 # <Iterator([XBOX, STADIA])> 283 ``` 284 """ 285 return Iterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
287 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 288 """Zips the iterator with another iterable. 289 290 Example 291 ------- 292 ```py 293 iterator = Iterator([1, 3, 5]) 294 other = Iterator([2, 4, 6]) 295 for item, other_item in iterator.zip(other): 296 print(item, other_item) 297 # <Iterator([(1, 2), (3, 4), (5, 6)])> 298 ``` 299 300 Parameters 301 ---------- 302 other: `Iterator[OtherItem]` 303 The iterable to zip with. 304 305 Raises 306 ------ 307 `StopIteration` 308 If no elements are left in the iterator. 309 """ 310 return Iterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
- other (
Iterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
312 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 313 """`True` if all items in the iterator match the predicate. 314 315 Example 316 ------- 317 ```py 318 iterator = Iterator([1, 2, 3]) 319 while iterator.all(lambda item: isinstance(item, int)): 320 print("Still all integers") 321 continue 322 # Still all integers 323 ``` 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
337 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 338 """`True` if any items in the iterator match the predicate. 339 340 Example 341 ------- 342 ```py 343 iterator = Iterator([1, 2, 3]) 344 if iterator.any(lambda item: isinstance(item, int)): 345 print("At least one item is an int.") 346 # At least one item is an int. 347 ``` 348 349 Parameters 350 ---------- 351 predicate: `collections.Callable[[Item], bool]` 352 The function to test each item in the iterator. 353 354 Raises 355 ------ 356 `StopIteration` 357 If no elements are left in the iterator. 358 """ 359 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
# At least one item is an int.
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
361 def sort( 362 self, 363 *, 364 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 365 reverse: bool = False, 366 ) -> Iterator[Item]: 367 """Sorts the iterator. 368 369 Example 370 ------- 371 ```py 372 iterator = Iterator([3, 1, 6, 7]) 373 print(iterator.sort(key=lambda item: item)) 374 # <Iterator([1, 3, 6, 7])> 375 ``` 376 377 Parameters 378 ---------- 379 key: `collections.Callable[[Item], Any]` 380 The function to sort by. 381 reverse: `bool` 382 Whether to reverse the sort. 383 384 Raises 385 ------ 386 `StopIteration` 387 If no elements are left in the iterator. 388 """ 389 return Iterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
391 def first(self) -> Item: 392 """Returns the first item in the iterator. 393 394 Example 395 ------- 396 ```py 397 iterator = Iterator([3, 1, 6, 7]) 398 print(iterator.first()) 399 3 400 ``` 401 402 Raises 403 ------ 404 `StopIteration` 405 If no elements are left in the iterator. 406 """ 407 return self.take(1).next()
Returns the first item in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
StopIteration: If no elements are left in the iterator.
409 def last(self) -> Item: 410 """Returns the last item in the iterator. 411 412 Example 413 ------ 414 ```py 415 it = Iterator((1, 2, 3)) 416 assert it.first() == 1 and it.last() == 3 417 ``` 418 """ 419 return self.reversed().first()
Returns the last item in the iterator.
Example
it = Iterator((1, 2, 3))
assert it.first() == 1 and it.last() == 3
421 def reversed(self) -> Iterator[Item]: 422 """Returns a new iterator that yields the items in the iterator in reverse order. 423 424 Example 425 ------- 426 ```py 427 iterator = Iterator([3, 1, 6, 7]) 428 print(iterator.reversed()) 429 # <Iterator([7, 6, 1, 3])> 430 ``` 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return Iterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
StopIteration: If no elements are left in the iterator.
439 def count(self) -> int: 440 """Returns the number of items in the iterator. 441 442 Example 443 ------- 444 ```py 445 iterator = Iterator([3, 1, 6, 7]) 446 print(iterator.count()) 447 4 448 ``` 449 """ 450 count = 0 451 for _ in self: 452 count += 1 453 454 return count
Returns the number of items in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
456 def union(self, other: Iterator[Item]) -> Iterator[Item]: 457 """Returns a new iterator that yields all items from both iterators. 458 459 Example 460 ------- 461 ```py 462 iterator = Iterator([1, 2, 3]) 463 other = Iterator([4, 5, 6]) 464 print(iterator.union(other)) 465 # <Iterator([1, 2, 3, 4, 5, 6])> 466 ``` 467 468 Parameters 469 ---------- 470 other: `Iterator[Item]` 471 The iterable to union with. 472 473 Raises 474 ------ 475 `StopIteration` 476 If no elements are left in the iterator. 477 """ 478 return Iterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- other (
Iterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
480 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 481 """Calls the function on each item in the iterator. 482 483 Example 484 ------- 485 ```py 486 iterator = Iterator([1, 2, 3]) 487 iterator.for_each(lambda item: print(item)) 488 # 1 489 # 2 490 # 3 491 ``` 492 493 Parameters 494 ---------- 495 func: `typeshed.Callable[[Item], None]` 496 The function to call on each item in the iterator. 497 """ 498 for item in self: 499 func(item)
Calls the function on each item in the iterator.
Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
501 async def async_for_each( 502 self, 503 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 504 ) -> None: 505 """Calls the async function on each item in the iterator concurrently. 506 507 Example 508 ------- 509 ```py 510 async def signup(username: str) -> None: 511 async with aiohttp.request('POST', '...') as r: 512 # Actual logic. 513 ... 514 515 async def main(): 516 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 517 await users.async_for_each(lambda username: signup(username)) 518 ``` 519 520 Parameters 521 ---------- 522 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 523 The async function to call on each item in the iterator. 524 """ 525 await _helpers.awaits(*(func(item) for item in self))
Calls the async function on each item in the iterator concurrently.
Example
async def signup(username: str) -> None:
async with aiohttp.request('POST', '...') as r:
# Actual logic.
...
async def main():
users = aiobungie.into_iter(["user_danny", "user_jojo"])
await users.async_for_each(lambda username: signup(username))
Parameters
- func (
collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
527 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 528 """Returns a new iterator that yields tuples of the index and item. 529 530 Example 531 ------- 532 ```py 533 iterator = Iterator([1, 2, 3]) 534 for index, item in iterator.enumerate(): 535 print(index, item) 536 # 0 1 537 # 1 2 538 # 2 3 539 ``` 540 541 Raises 542 ------ 543 `StopIteration` 544 If no elements are left in the iterator. 545 """ 546 return Iterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
print(index, item)
# 0 1
# 1 2
# 2 3
Raises
StopIteration: If no elements are left in the iterator.
701@typing.final 702class MembershipOption(int, Enum): 703 """A enum for GroupV2 membership options.""" 704 705 REVIEWD = 0 706 OPEN = 1 707 CLOSED = 2
A enum for GroupV2 membership options.
449@typing.final 450class MembershipType(int, Enum): 451 """An Enum for Bungie membership types.""" 452 453 NONE = 0 454 XBOX = 1 455 PSN = 2 456 STEAM = 3 457 BLIZZARD = 4 458 STADIA = 5 459 EPIC_GAMES_STORE = 6 460 DEMON = 10 461 BUNGIE = 254 462 ALL = -1
An Enum for Bungie membership types.
182@attrs.define(auto_exc=True) 183class MembershipTypeError(BadRequest): 184 """A bad request error raised when passing wrong membership to the request. 185 186 Those fields are useful since it returns the correct membership and id which can be used 187 to make the request again with those fields. 188 189 Example 190 ------- 191 ```py 192 try: 193 profile = await client.fetch_profile( 194 member_id=1, 195 type=aiobungie.MembershipType.STADIA, 196 components=[] 197 ) 198 199 # Membership type is wrong! 200 except aiobungie.MembershipTypeError as err: 201 correct_membersip = err.into_membership() 202 profile_id = err.membership_id 203 204 # Recall the method. 205 profile = await client.fetch_profile( 206 member_id=profile_id, 207 type=correct_membership, 208 components=[] 209 ) 210 ``` 211 """ 212 213 membership_type: str 214 """The errored membership type passed to the request.""" 215 216 membership_id: int 217 """The errored user's membership id.""" 218 219 required_membership: str 220 """The required correct membership for errored user.""" 221 222 def into_membership(self, value: str | None = None) -> enums.MembershipType: 223 """Turn the required membership from `str` into `aiobungie.Membership` type. 224 225 If value parameter is not provided it will fall back to the required membership. 226 """ 227 if value is None: 228 return _determine_membership(self.required_membership) 229 return _determine_membership(value) 230 231 def __str__(self) -> str: 232 return ( 233 f"Expected membership: {self.into_membership().name.replace('_', '').title()}, " 234 f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}" 235 ) 236 237 def __int__(self) -> int: 238 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
Example
try:
profile = await client.fetch_profile(
member_id=1,
type=aiobungie.MembershipType.STADIA,
components=[]
)
# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
correct_membersip = err.into_membership()
profile_id = err.membership_id
# Recall the method.
profile = await client.fetch_profile(
member_id=profile_id,
type=correct_membership,
components=[]
)
2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
222 def into_membership(self, value: str | None = None) -> enums.MembershipType: 223 """Turn the required membership from `str` into `aiobungie.Membership` type. 224 225 If value parameter is not provided it will fall back to the required membership. 226 """ 227 if value is None: 228 return _determine_membership(self.required_membership) 229 return _determine_membership(value)
Turn the required membership from str into aiobungie.Membership type.
If value parameter is not provided it will fall back to the required membership.
Inherited Members
- builtins.BaseException
- with_traceback
- args
494@typing.final 495class MilestoneType(int, Enum): 496 """An Enum for Destiny 2 milestone types.""" 497 498 UNKNOWN = 0 499 TUTORIAL = 1 500 ONETIME = 2 501 WEEKLY = 3 502 DAILY = 4 503 SPECIAL = 5
An Enum for Destiny 2 milestone types.
146@attrs.define(auto_exc=True) 147class NotFound(HTTPException): 148 """Raised when an unknown resource was not found.""" 149 150 http_status: http.HTTPStatus = attrs.field( 151 default=http.HTTPStatus.NOT_FOUND, init=False 152 )
Raised when an unknown resource was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
93@typing.final 94class ObjectiveUIStyle(int, enums.Enum): 95 NONE = 0 96 HIGHLIGHTED = 1 97 CRAFTING_WEAPON_LEVEL = 2 98 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 99 CRAFTING_WEAPON_TIMESTAMP = 4 100 CRAFTING_MEMENTOS = 5 101 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
219@typing.final 220class Place(int, Enum): 221 """An Enum for Destiny 2 Places and NOT Planets""" 222 223 ORBIT = 2961497387 224 SOCIAL = 4151112093 225 LIGHT_HOUSE = 4276116472 226 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
184@typing.final 185class Planet(int, Enum): 186 """An Enum for all available planets in Destiny 2.""" 187 188 UNKNOWN = 0 189 """Unknown space""" 190 191 EARTH = 3747705955 192 """Earth""" 193 194 DREAMING_CITY = 2877881518 195 """The Dreaming city.""" 196 197 NESSUS = 3526908984 198 """Nessus""" 199 200 MOON = 3325508439 201 """The Moon""" 202 203 COSMODROME = 3990611421 204 """The Cosmodrome""" 205 206 TANGLED_SHORE = 3821439926 207 """The Tangled Shore""" 208 209 VENUS = 3871070152 210 """Venus""" 211 212 EAZ = 541863059 # Exclusive event. 213 """European Aerial Zone""" 214 215 EUROPA = 1729879943 216 """Europa"""
An Enum for all available planets in Destiny 2.
671@typing.final 672class Presence(int, Enum): 673 """An enum for a bungie friend status.""" 674 675 OFFLINE_OR_UNKNOWN = 0 676 ONLINE = 1
An enum for a bungie friend status.
759@typing.final 760class PrivacySetting(int, Enum): 761 """An enum for players's privacy settings.""" 762 763 OPEN = 0 764 CLAN_AND_FRIENDS = 1 765 FRIENDS_ONLY = 2 766 INVITE_ONLY = 3 767 CLOSED = 4
An enum for players's privacy settings.
305class RESTClient(interfaces.RESTInterface): 306 """A RESTful client implementation for Bungie's API. 307 308 This client is designed to only make HTTP requests and return JSON objects 309 to provide RESTful functionality. 310 311 This client is the core for `aiobungie.Client` which deserialize those returned JSON objects 312 using the factory into Pythonic data classes objects which provide Python functionality. 313 314 Example 315 ------- 316 ```py 317 import aiobungie 318 319 client = aiobungie.RESTClient("TOKEN") 320 async with client: 321 response = await client.fetch_clan_members(4389205) 322 for member in response['results']: 323 for key, value in member['destinyUserInfo'].items(): 324 print(key, value) 325 ``` 326 327 Parameters 328 ---------- 329 token : `str` 330 A valid application token from Bungie's developer portal. 331 332 Other Parameters 333 ---------------- 334 max_retries : `int` 335 The max retries number to retry if the request hit a `5xx` status code. 336 client_secret : `str | None` 337 An optional application client secret, 338 This is only needed if you're fetching OAuth2 tokens with this client. 339 client_id : `int | None` 340 An optional application client id, 341 This is only needed if you're fetching OAuth2 tokens with this client. 342 enable_debugging : `bool | str` 343 Whether to enable logging responses or not. 344 345 Logging Levels 346 -------------- 347 * `False`: This will disable logging. 348 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 349 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 350 """ 351 352 __slots__ = ( 353 "_token", 354 "_session", 355 "_lock", 356 "_max_retries", 357 "_client_secret", 358 "_client_id", 359 "_metadata", 360 "_dumps", 361 "_loads", 362 ) 363 364 def __init__( 365 self, 366 token: str, 367 /, 368 *, 369 client_secret: str | None = None, 370 client_id: int | None = None, 371 client_session: aiohttp.ClientSession | None = None, 372 dumps: typedefs.Dumps = helpers.dumps, 373 loads: typedefs.Loads = helpers.loads, 374 max_retries: int = 4, 375 enable_debugging: typing.Literal["TRACE"] | bool | int = False, 376 ) -> None: 377 self._session = client_session 378 self._lock: asyncio.Lock | None = None 379 self._client_secret = client_secret 380 self._client_id = client_id 381 self._token: str = token 382 self._max_retries = max_retries 383 self._dumps = dumps 384 self._loads = loads 385 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 386 387 self._set_debug_level(enable_debugging) 388 389 @property 390 def client_id(self) -> int | None: 391 return self._client_id 392 393 @property 394 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 395 return self._metadata 396 397 @property 398 def is_alive(self) -> bool: 399 return self._session is not None 400 401 @typing.final 402 async def close(self) -> None: 403 if self._session is None: 404 raise RuntimeError("REST client is not running.") 405 406 await self._session.close() 407 self._session = None 408 409 @typing.final 410 def open(self) -> None: 411 """Open a new client session. This is called internally with contextmanager usage.""" 412 if self._session: 413 raise RuntimeError("Cannot open REST client when it's already open.") 414 415 self._session = aiohttp.ClientSession( 416 connector=aiohttp.TCPConnector(), 417 connector_owner=True, 418 raise_for_status=False, 419 timeout=aiohttp.ClientTimeout(total=30.0), 420 ) 421 422 @typing.final 423 def enable_debugging( 424 self, 425 level: typing.Literal["TRACE"] | bool | int = False, 426 file: pathlib.Path | str | None = None, 427 /, 428 ) -> None: 429 self._set_debug_level(level, file) 430 431 @typing.final 432 async def static_request( 433 self, 434 method: RequestMethod | str, 435 path: str, 436 *, 437 auth: str | None = None, 438 json: collections.Mapping[str, typing.Any] | None = None, 439 ) -> typedefs.JSONIsh: 440 return await self._request(method, path, auth=auth, json=json) 441 442 @typing.final 443 def build_oauth2_url( 444 self, client_id: int | None = None 445 ) -> builders.OAuthURL | None: 446 client_id = client_id or self._client_id 447 if client_id is None: 448 return None 449 450 return builders.OAuthURL(client_id=client_id) 451 452 @staticmethod 453 def _set_debug_level( 454 level: typing.Literal["TRACE"] | bool | int = False, 455 file: pathlib.Path | str | None = None, 456 ) -> None: 457 file_handler = logging.FileHandler(file, mode="w") if file else None 458 if level == "TRACE" or level == TRACE: 459 logging.basicConfig( 460 level=TRACE, handlers=[file_handler] if file_handler else None 461 ) 462 463 elif level: 464 logging.basicConfig( 465 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 466 ) 467 468 async def _request( 469 self, 470 method: RequestMethod | str, 471 route: str, 472 *, 473 base: bool = False, 474 oauth2: bool = False, 475 auth: str | None = None, 476 unwrapping: typing.Literal["json", "read"] = "json", 477 json: collections.Mapping[str, typing.Any] | str | None = None, 478 params: collections.Mapping[str, typing.Any] | None = None, 479 headers: dict[str, typing.Any] | None = None, 480 ) -> typedefs.JSONIsh: 481 # This is not None when opening the client. 482 assert self._session is not None 483 484 retries: int = 0 485 headers = headers or {} 486 487 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 488 headers["X-API-KEY"] = self._token 489 490 if auth is not None: 491 headers[_AUTH_HEADER] = f"Bearer {auth}" 492 493 # Handling endpoints 494 endpoint = url.BASE 495 496 if not base: 497 endpoint = endpoint + url.REST_EP 498 499 if oauth2: 500 headers["Content-Type"] = "application/x-www-form-urlencoded" 501 endpoint = endpoint + url.TOKEN_EP 502 503 if self._lock is None: 504 self._lock = asyncio.Lock() 505 506 while True: 507 async with (stack := contextlib.AsyncExitStack()): 508 await stack.enter_async_context(self._lock) 509 510 data = self._dumps(json) if isinstance(json, dict) else json 511 # We make the request here. 512 taken_time = time.monotonic() 513 response = await self._session.request( 514 method=method, 515 url=f"{endpoint}/{route}", 516 headers=headers, 517 data=data, 518 params=params, 519 ) 520 response_time = (time.monotonic() - taken_time) * 1_000 521 522 _LOG.debug( 523 "%s %s %s Time %.4fms", 524 method, 525 f"{endpoint}/{route}", 526 f"{response.status} {response.reason}", 527 response_time, 528 ) 529 530 await self._handle_ratelimit(response, method, route) 531 532 if response.status == http.HTTPStatus.NO_CONTENT: 533 return None 534 535 if 300 > response.status >= 200: 536 if unwrapping == "read": 537 # We need to read the bytes for the manifest response. 538 return await response.read() 539 540 if response.content_type == _APP_JSON: 541 # json_data = self._loads(await response.read()) 542 json_data = self._loads(await response.read()) 543 544 _LOG.debug( 545 "%s %s %s Time %.4fms", 546 method, 547 f"{endpoint}/{route}", 548 f"{response.status} {response.reason}", 549 response_time, 550 ) 551 552 if _LOG.isEnabledFor(TRACE): 553 cloned = headers.copy() 554 cloned.update(response.headers) # type: ignore 555 556 _LOG.log( 557 TRACE, 558 "%s", 559 error.stringify_http_message(cloned), 560 ) 561 562 # Return the response. 563 # oauth2 responses are not packed inside a Response object. 564 if oauth2: 565 return json_data # type: ignore[no-any-return] 566 567 return json_data["Response"] # type: ignore 568 569 if ( 570 response.status in _RETRY_5XX and retries < self._max_retries # noqa: W503 571 ): 572 backoff_ = backoff.ExponentialBackOff(maximum=6) 573 sleep_time = next(backoff_) 574 _LOG.warning( 575 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 576 response.status, 577 response.reason, 578 sleep_time, 579 self._max_retries - retries, 580 ) 581 582 retries += 1 583 await asyncio.sleep(sleep_time) 584 continue 585 586 raise await error.raise_error(response) 587 588 async def __aenter__(self) -> RESTClient: 589 self.open() 590 return self 591 592 async def __aexit__( 593 self, 594 exception_type: type[BaseException] | None, 595 exception: BaseException | None, 596 exception_traceback: types.TracebackType | None, 597 ) -> None: 598 await self.close() 599 600 # We don't want this to be super complicated. 601 @typing.final 602 async def _handle_ratelimit( 603 self, 604 response: aiohttp.ClientResponse, 605 method: str, 606 route: str, 607 ) -> None: 608 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 609 return 610 611 if response.content_type != _APP_JSON: 612 raise error.HTTPError( 613 f"Being ratelimited on non JSON request, {response.content_type}.", 614 http.HTTPStatus.TOO_MANY_REQUESTS, 615 ) 616 617 json: typedefs.JSONObject = self._loads(await response.read()) # type: ignore 618 retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1 619 max_calls: int = 0 620 621 while True: 622 if max_calls == 10: 623 # Max retries by default. We raise an error here. 624 raise error.RateLimitedError( 625 body=json, 626 url=str(response.real_url), 627 retry_after=retry_after, 628 ) 629 630 # We sleep for a little bit to avoid funky behavior. 631 _LOG.warning( 632 "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.", 633 method, 634 route, 635 retry_after, 636 ) 637 await asyncio.sleep(retry_after) 638 max_calls += 1 639 continue 640 641 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 642 if not isinstance(self._client_secret, (str, int)): 643 raise TypeError( 644 "Expected (str, int) for client secret " 645 f"but got {type(self._client_secret).__name__}" # type: ignore 646 ) 647 648 headers = { 649 "client_secret": self._client_secret, 650 } 651 652 data = ( 653 f"grant_type=authorization_code&code={code}" 654 f"&client_id={self._client_id}&client_secret={self._client_secret}" 655 ) 656 657 response = await self._request( 658 RequestMethod.POST, "", headers=headers, json=data, oauth2=True 659 ) 660 assert isinstance(response, dict) 661 return builders.OAuth2Response.build_response(response) 662 663 async def refresh_access_token( 664 self, refresh_token: str, / 665 ) -> builders.OAuth2Response: 666 if not isinstance(self._client_secret, (int, str)): 667 raise TypeError( 668 f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}" # type: ignore 669 ) 670 671 data = { 672 "grant_type": "refresh_token", 673 "refresh_token": refresh_token, 674 "client_id": self._client_id, 675 "client_secret": self._client_secret, 676 "Content-Type": "application/x-www-form-urlencoded", 677 } 678 679 response = await self._request(RequestMethod.POST, "", json=data, oauth2=True) 680 assert isinstance(response, dict) 681 return builders.OAuth2Response.build_response(response) 682 683 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 684 resp = await self._request( 685 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 686 ) 687 assert isinstance(resp, dict) 688 return resp 689 690 async def fetch_user_themes(self) -> typedefs.JSONArray: 691 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 692 assert isinstance(resp, list) 693 return resp 694 695 async def fetch_membership_from_id( 696 self, 697 id: int, 698 type: enums.MembershipType | int = enums.MembershipType.NONE, 699 /, 700 ) -> typedefs.JSONObject: 701 resp = await self._request( 702 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 703 ) 704 assert isinstance(resp, dict) 705 return resp 706 707 async def fetch_membership( 708 self, 709 name: str, 710 code: int, 711 type: enums.MembershipType | int = enums.MembershipType.ALL, 712 /, 713 ) -> typedefs.JSONArray: 714 resp = await self._request( 715 RequestMethod.POST, 716 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 717 json={"displayName": name, "displayNameCode": code}, 718 ) 719 assert isinstance(resp, list) 720 return resp 721 722 async def search_users(self, name: str, /) -> typedefs.JSONObject: 723 resp = await self._request( 724 RequestMethod.POST, 725 "User/Search/GlobalName/0", 726 json={"displayNamePrefix": name}, 727 ) 728 assert isinstance(resp, dict) 729 return resp 730 731 async def fetch_clan_from_id( 732 self, id: int, /, access_token: str | None = None 733 ) -> typedefs.JSONObject: 734 resp = await self._request( 735 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 736 ) 737 assert isinstance(resp, dict) 738 return resp 739 740 async def fetch_clan( 741 self, 742 name: str, 743 /, 744 access_token: str | None = None, 745 *, 746 type: enums.GroupType | int = enums.GroupType.CLAN, 747 ) -> typedefs.JSONObject: 748 resp = await self._request( 749 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 750 ) 751 assert isinstance(resp, dict) 752 return resp 753 754 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 755 resp = await self._request( 756 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 757 ) 758 assert isinstance(resp, dict) 759 return resp 760 761 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 762 resp = await self._request( 763 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 764 ) 765 assert isinstance(resp, list) 766 return resp 767 768 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 769 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 770 assert isinstance(resp, dict) 771 return resp 772 773 async def fetch_character( 774 self, 775 member_id: int, 776 membership_type: enums.MembershipType | int, 777 character_id: int, 778 components: list[enums.ComponentType], 779 auth: str | None = None, 780 ) -> typedefs.JSONObject: 781 collector = _collect_components(components) 782 response = await self._request( 783 RequestMethod.GET, 784 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 785 f"Character/{character_id}/?components={collector}", 786 auth=auth, 787 ) 788 assert isinstance(response, dict) 789 return response 790 791 async def fetch_activities( 792 self, 793 member_id: int, 794 character_id: int, 795 mode: enums.GameMode | int, 796 membership_type: enums.MembershipType | int = enums.MembershipType.ALL, 797 *, 798 page: int = 0, 799 limit: int = 1, 800 ) -> typedefs.JSONObject: 801 resp = await self._request( 802 RequestMethod.GET, 803 f"Destiny2/{int(membership_type)}/Account/" 804 f"{member_id}/Character/{character_id}/Stats/Activities" 805 f"/?mode={int(mode)}&count={limit}&page={page}", 806 ) 807 assert isinstance(resp, dict) 808 return resp 809 810 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 811 resp = await self._request( 812 RequestMethod.GET, 813 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 814 ) 815 assert isinstance(resp, dict) 816 return resp 817 818 async def fetch_profile( 819 self, 820 membership_id: int, 821 type: enums.MembershipType | int, 822 components: list[enums.ComponentType], 823 auth: str | None = None, 824 ) -> typedefs.JSONObject: 825 collector = _collect_components(components) 826 response = await self._request( 827 RequestMethod.GET, 828 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 829 auth=auth, 830 ) 831 assert isinstance(response, dict) 832 return response 833 834 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 835 response = await self._request( 836 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 837 ) 838 assert isinstance(response, dict) 839 return response 840 841 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 842 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 843 assert isinstance(resp, dict) 844 return resp 845 846 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 847 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 848 assert isinstance(resp, dict) 849 return resp 850 851 async def fetch_groups_for_member( 852 self, 853 member_id: int, 854 member_type: enums.MembershipType | int, 855 /, 856 *, 857 filter: int = 0, 858 group_type: enums.GroupType | int = enums.GroupType.CLAN, 859 ) -> typedefs.JSONObject: 860 resp = await self._request( 861 RequestMethod.GET, 862 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 863 ) 864 assert isinstance(resp, dict) 865 return resp 866 867 async def fetch_potential_groups_for_member( 868 self, 869 member_id: int, 870 member_type: enums.MembershipType | int, 871 /, 872 *, 873 filter: int = 0, 874 group_type: enums.GroupType | int = enums.GroupType.CLAN, 875 ) -> typedefs.JSONObject: 876 resp = await self._request( 877 RequestMethod.GET, 878 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 879 ) 880 assert isinstance(resp, dict) 881 return resp 882 883 async def fetch_clan_members( 884 self, 885 clan_id: int, 886 /, 887 *, 888 name: str | None = None, 889 type: enums.MembershipType | int = enums.MembershipType.NONE, 890 ) -> typedefs.JSONObject: 891 resp = await self._request( 892 RequestMethod.GET, 893 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 894 ) 895 assert isinstance(resp, dict) 896 return resp 897 898 async def fetch_hardlinked_credentials( 899 self, 900 credential: int, 901 type: enums.CredentialType | int = enums.CredentialType.STEAMID, 902 /, 903 ) -> typedefs.JSONObject: 904 resp = await self._request( 905 RequestMethod.GET, 906 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 907 ) 908 assert isinstance(resp, dict) 909 return resp 910 911 async def fetch_user_credentials( 912 self, access_token: str, membership_id: int, / 913 ) -> typedefs.JSONArray: 914 resp = await self._request( 915 RequestMethod.GET, 916 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 917 auth=access_token, 918 ) 919 assert isinstance(resp, list) 920 return resp 921 922 async def insert_socket_plug( 923 self, 924 action_token: str, 925 /, 926 instance_id: int, 927 plug: builders.PlugSocketBuilder | collections.Mapping[str, int], 928 character_id: int, 929 membership_type: enums.MembershipType | int, 930 ) -> typedefs.JSONObject: 931 if isinstance(plug, builders.PlugSocketBuilder): 932 plug = plug.collect() 933 934 body = { 935 "actionToken": action_token, 936 "itemInstanceId": instance_id, 937 "plug": plug, 938 "characterId": character_id, 939 "membershipType": int(membership_type), 940 } 941 resp = await self._request( 942 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 943 ) 944 assert isinstance(resp, dict) 945 return resp 946 947 async def insert_socket_plug_free( 948 self, 949 access_token: str, 950 /, 951 instance_id: int, 952 plug: builders.PlugSocketBuilder | collections.Mapping[str, int], 953 character_id: int, 954 membership_type: enums.MembershipType | int, 955 ) -> typedefs.JSONObject: 956 if isinstance(plug, builders.PlugSocketBuilder): 957 plug = plug.collect() 958 959 body = { 960 "itemInstanceId": instance_id, 961 "plug": plug, 962 "characterId": character_id, 963 "membershipType": int(membership_type), 964 } 965 resp = await self._request( 966 RequestMethod.POST, 967 "Destiny2/Actions/Items/InsertSocketPlugFree", 968 json=body, 969 auth=access_token, 970 ) 971 assert isinstance(resp, dict) 972 return resp 973 974 async def set_item_lock_state( 975 self, 976 access_token: str, 977 state: bool, 978 /, 979 item_id: int, 980 character_id: int, 981 membership_type: enums.MembershipType | int, 982 ) -> int: 983 body = { 984 "state": state, 985 "itemId": item_id, 986 "characterId": character_id, 987 "membershipType": int(membership_type), 988 } 989 response = await self._request( 990 RequestMethod.POST, 991 "Destiny2/Actions/Items/SetLockState", 992 json=body, 993 auth=access_token, 994 ) 995 assert isinstance(response, int) 996 return response 997 998 async def set_quest_track_state( 999 self, 1000 access_token: str, 1001 state: bool, 1002 /, 1003 item_id: int, 1004 character_id: int, 1005 membership_type: enums.MembershipType | int, 1006 ) -> int: 1007 body = { 1008 "state": state, 1009 "itemId": item_id, 1010 "characterId": character_id, 1011 "membership_type": int(membership_type), 1012 } 1013 response = await self._request( 1014 RequestMethod.POST, 1015 "Destiny2/Actions/Items/SetTrackedState", 1016 json=body, 1017 auth=access_token, 1018 ) 1019 assert isinstance(response, int) 1020 return response 1021 1022 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1023 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1024 assert isinstance(path, dict) 1025 return path 1026 1027 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1028 _ensure_manifest_language(language) 1029 1030 content = await self.fetch_manifest_path() 1031 resp = await self._request( 1032 RequestMethod.GET, 1033 content["mobileWorldContentPaths"][language], 1034 unwrapping="read", 1035 base=True, 1036 ) 1037 assert isinstance(resp, bytes) 1038 return resp 1039 1040 async def download_sqlite_manifest( 1041 self, 1042 language: str = "en", 1043 name: str = "manifest", 1044 path: pathlib.Path | str = ".", 1045 *, 1046 force: bool = False, 1047 ) -> pathlib.Path: 1048 complete_path = _get_path(name, path, sql=True) 1049 1050 if complete_path.exists() and force: 1051 if force: 1052 _LOG.info( 1053 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1054 ) 1055 complete_path.unlink(missing_ok=True) 1056 1057 return await self.download_sqlite_manifest( 1058 language, name, path, force=force 1059 ) 1060 1061 else: 1062 raise FileExistsError( 1063 "Manifest file already exists, " 1064 "To force download, set the `force` parameter to `True`." 1065 ) 1066 1067 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1068 data_bytes = await self.read_manifest_bytes(language) 1069 await asyncio.get_running_loop().run_in_executor( 1070 None, _write_sqlite_bytes, data_bytes, path, name 1071 ) 1072 return _get_path(name, path, sql=True) 1073 1074 async def download_json_manifest( 1075 self, 1076 file_name: str = "manifest", 1077 path: str | pathlib.Path = ".", 1078 language: str = "en", 1079 ) -> pathlib.Path: 1080 _ensure_manifest_language(language) 1081 1082 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1083 1084 content = await self.fetch_manifest_path() 1085 json_bytes = await self._request( 1086 RequestMethod.GET, 1087 content["jsonWorldContentPaths"][language], 1088 unwrapping="read", 1089 base=True, 1090 ) 1091 1092 await asyncio.get_running_loop().run_in_executor( 1093 None, _write_json_bytes, json_bytes, file_name, path 1094 ) 1095 _LOG.info("Finished downloading manifest JSON.") 1096 return _get_path(file_name, path) 1097 1098 async def fetch_manifest_version(self) -> str: 1099 # This is guaranteed str. 1100 return (await self.fetch_manifest_path())["version"] # type: ignore[no-any-return] 1101 1102 async def fetch_linked_profiles( 1103 self, 1104 member_id: int, 1105 member_type: enums.MembershipType | int, 1106 /, 1107 *, 1108 all: bool = False, 1109 ) -> typedefs.JSONObject: 1110 resp = await self._request( 1111 RequestMethod.GET, 1112 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1113 ) 1114 assert isinstance(resp, dict) 1115 return resp 1116 1117 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1118 resp = await self._request( 1119 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1120 ) 1121 assert isinstance(resp, dict) 1122 return resp 1123 1124 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1125 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1126 assert isinstance(resp, dict) 1127 return resp 1128 1129 async def fetch_public_milestone_content( 1130 self, milestone_hash: int, / 1131 ) -> typedefs.JSONObject: 1132 resp = await self._request( 1133 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1134 ) 1135 assert isinstance(resp, dict) 1136 return resp 1137 1138 async def fetch_current_user_memberships( 1139 self, access_token: str, / 1140 ) -> typedefs.JSONObject: 1141 resp = await self._request( 1142 RequestMethod.GET, 1143 "User/GetMembershipsForCurrentUser/", 1144 auth=access_token, 1145 ) 1146 assert isinstance(resp, dict) 1147 return resp 1148 1149 async def equip_item( 1150 self, 1151 access_token: str, 1152 /, 1153 item_id: int, 1154 character_id: int, 1155 membership_type: enums.MembershipType | int, 1156 ) -> None: 1157 payload = { 1158 "itemId": item_id, 1159 "characterId": character_id, 1160 "membershipType": int(membership_type), 1161 } 1162 1163 await self._request( 1164 RequestMethod.POST, 1165 "Destiny2/Actions/Items/EquipItem/", 1166 json=payload, 1167 auth=access_token, 1168 ) 1169 1170 async def equip_items( 1171 self, 1172 access_token: str, 1173 /, 1174 item_ids: collections.Sequence[int], 1175 character_id: int, 1176 membership_type: enums.MembershipType | int, 1177 ) -> None: 1178 payload = { 1179 "itemIds": item_ids, 1180 "characterId": character_id, 1181 "membershipType": int(membership_type), 1182 } 1183 await self._request( 1184 RequestMethod.POST, 1185 "Destiny2/Actions/Items/EquipItems/", 1186 json=payload, 1187 auth=access_token, 1188 ) 1189 1190 async def ban_clan_member( 1191 self, 1192 access_token: str, 1193 /, 1194 group_id: int, 1195 membership_id: int, 1196 membership_type: enums.MembershipType | int, 1197 *, 1198 length: int = 0, 1199 comment: str | None = None, 1200 ) -> None: 1201 payload = {"comment": str(comment), "length": length} 1202 await self._request( 1203 RequestMethod.POST, 1204 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1205 json=payload, 1206 auth=access_token, 1207 ) 1208 1209 async def unban_clan_member( 1210 self, 1211 access_token: str, 1212 /, 1213 group_id: int, 1214 membership_id: int, 1215 membership_type: enums.MembershipType | int, 1216 ) -> None: 1217 await self._request( 1218 RequestMethod.POST, 1219 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1220 auth=access_token, 1221 ) 1222 1223 async def kick_clan_member( 1224 self, 1225 access_token: str, 1226 /, 1227 group_id: int, 1228 membership_id: int, 1229 membership_type: enums.MembershipType | int, 1230 ) -> typedefs.JSONObject: 1231 resp = await self._request( 1232 RequestMethod.POST, 1233 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1234 auth=access_token, 1235 ) 1236 assert isinstance(resp, dict) 1237 return resp 1238 1239 async def edit_clan( 1240 self, 1241 access_token: str, 1242 /, 1243 group_id: int, 1244 *, 1245 name: str | None = None, 1246 about: str | None = None, 1247 motto: str | None = None, 1248 theme: str | None = None, 1249 tags: collections.Sequence[str] | None = None, 1250 is_public: bool | None = None, 1251 locale: str | None = None, 1252 avatar_image_index: int | None = None, 1253 membership_option: enums.MembershipOption | int | None = None, 1254 allow_chat: bool | None = None, 1255 chat_security: typing.Literal[0, 1] | None = None, 1256 call_sign: str | None = None, 1257 homepage: typing.Literal[0, 1, 2] | None = None, 1258 enable_invite_messaging_for_admins: bool | None = None, 1259 default_publicity: typing.Literal[0, 1, 2] | None = None, 1260 is_public_topic_admin: bool | None = None, 1261 ) -> None: 1262 payload = { 1263 "name": name, 1264 "about": about, 1265 "motto": motto, 1266 "theme": theme, 1267 "tags": tags, 1268 "isPublic": is_public, 1269 "avatarImageIndex": avatar_image_index, 1270 "isPublicTopicAdminOnly": is_public_topic_admin, 1271 "allowChat": allow_chat, 1272 "chatSecurity": chat_security, 1273 "callsign": call_sign, 1274 "homepage": homepage, 1275 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1276 "defaultPublicity": default_publicity, 1277 "locale": locale, 1278 } 1279 if membership_option is not None: 1280 payload["membershipOption"] = int(membership_option) 1281 1282 await self._request( 1283 RequestMethod.POST, 1284 f"GroupV2/{group_id}/Edit", 1285 json=payload, 1286 auth=access_token, 1287 ) 1288 1289 async def edit_clan_options( 1290 self, 1291 access_token: str, 1292 /, 1293 group_id: int, 1294 *, 1295 invite_permissions_override: bool | None = None, 1296 update_culture_permissionOverride: bool | None = None, 1297 host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None, 1298 update_banner_permission_override: bool | None = None, 1299 join_level: enums.ClanMemberType | int | None = None, 1300 ) -> None: 1301 payload = { 1302 "InvitePermissionOverride": invite_permissions_override, 1303 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1304 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1305 "UpdateBannerPermissionOverride": update_banner_permission_override, 1306 "JoinLevel": int(join_level) if join_level else None, 1307 } 1308 1309 await self._request( 1310 RequestMethod.POST, 1311 f"GroupV2/{group_id}/EditFounderOptions", 1312 json=payload, 1313 auth=access_token, 1314 ) 1315 1316 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1317 resp = await self._request( 1318 RequestMethod.GET, 1319 "Social/Friends/", 1320 auth=access_token, 1321 ) 1322 assert isinstance(resp, dict) 1323 return resp 1324 1325 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1326 resp = await self._request( 1327 RequestMethod.GET, 1328 "Social/Friends/Requests", 1329 auth=access_token, 1330 ) 1331 assert isinstance(resp, dict) 1332 return resp 1333 1334 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1335 await self._request( 1336 RequestMethod.POST, 1337 f"Social/Friends/Requests/Accept/{member_id}", 1338 auth=access_token, 1339 ) 1340 1341 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1342 await self._request( 1343 RequestMethod.POST, 1344 f"Social/Friends/Add/{member_id}", 1345 auth=access_token, 1346 ) 1347 1348 async def decline_friend_request( 1349 self, access_token: str, /, member_id: int 1350 ) -> None: 1351 await self._request( 1352 RequestMethod.POST, 1353 f"Social/Friends/Requests/Decline/{member_id}", 1354 auth=access_token, 1355 ) 1356 1357 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1358 await self._request( 1359 RequestMethod.POST, 1360 f"Social/Friends/Remove/{member_id}", 1361 auth=access_token, 1362 ) 1363 1364 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1365 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1366 await self._request( 1367 RequestMethod.POST, 1368 f"Social/Friends/Requests/Remove/{member_id}", 1369 auth=access_token, 1370 ) 1371 1372 async def approve_all_pending_group_users( 1373 self, 1374 access_token: str, 1375 /, 1376 group_id: int, 1377 message: str | None = None, 1378 ) -> None: 1379 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1380 await self._request( 1381 RequestMethod.POST, 1382 f"GroupV2/{group_id}/Members/ApproveAll", 1383 auth=access_token, 1384 json={"message": str(message)}, 1385 ) 1386 1387 async def deny_all_pending_group_users( 1388 self, 1389 access_token: str, 1390 /, 1391 group_id: int, 1392 *, 1393 message: str | None = None, 1394 ) -> None: 1395 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1396 await self._request( 1397 RequestMethod.POST, 1398 f"GroupV2/{group_id}/Members/DenyAll", 1399 auth=access_token, 1400 json={"message": str(message)}, 1401 ) 1402 1403 async def add_optional_conversation( 1404 self, 1405 access_token: str, 1406 /, 1407 group_id: int, 1408 *, 1409 name: str | None = None, 1410 security: typing.Literal[0, 1] = 0, 1411 ) -> None: 1412 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1413 payload = {"chatName": str(name), "chatSecurity": security} 1414 await self._request( 1415 RequestMethod.POST, 1416 f"GroupV2/{group_id}/OptionalConversations/Add", 1417 json=payload, 1418 auth=access_token, 1419 ) 1420 1421 async def edit_optional_conversation( 1422 self, 1423 access_token: str, 1424 /, 1425 group_id: int, 1426 conversation_id: int, 1427 *, 1428 name: str | None = None, 1429 security: typing.Literal[0, 1] = 0, 1430 enable_chat: bool = False, 1431 ) -> None: 1432 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1433 payload = { 1434 "chatEnabled": enable_chat, 1435 "chatName": str(name), 1436 "chatSecurity": security, 1437 } 1438 await self._request( 1439 RequestMethod.POST, 1440 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1441 json=payload, 1442 auth=access_token, 1443 ) 1444 1445 async def transfer_item( 1446 self, 1447 access_token: str, 1448 /, 1449 item_id: int, 1450 item_hash: int, 1451 character_id: int, 1452 member_type: enums.MembershipType | int, 1453 *, 1454 stack_size: int = 1, 1455 vault: bool = False, 1456 ) -> None: 1457 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1458 payload = { 1459 "characterId": character_id, 1460 "membershipType": int(member_type), 1461 "itemId": item_id, 1462 "itemReferenceHash": item_hash, 1463 "stackSize": stack_size, 1464 "transferToVault": vault, 1465 } 1466 await self._request( 1467 RequestMethod.POST, 1468 "Destiny2/Actions/Items/TransferItem", 1469 json=payload, 1470 auth=access_token, 1471 ) 1472 1473 async def pull_item( 1474 self, 1475 access_token: str, 1476 /, 1477 item_id: int, 1478 item_hash: int, 1479 character_id: int, 1480 member_type: enums.MembershipType | int, 1481 *, 1482 stack_size: int = 1, 1483 vault: bool = False, 1484 ) -> None: 1485 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1486 payload = { 1487 "characterId": character_id, 1488 "membershipType": int(member_type), 1489 "itemId": item_id, 1490 "itemReferenceHash": item_hash, 1491 "stackSize": stack_size, 1492 "transferToVault": vault, 1493 } 1494 await self._request( 1495 RequestMethod.POST, 1496 "Destiny2/Actions/Items/PullFromPostmaster", 1497 json=payload, 1498 auth=access_token, 1499 ) 1500 1501 async def fetch_fireteams( 1502 self, 1503 activity_type: fireteams.FireteamActivity | int, 1504 *, 1505 platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY, 1506 language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL, 1507 date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL, 1508 page: int = 0, 1509 slots_filter: int = 0, 1510 ) -> typedefs.JSONObject: 1511 resp = await self._request( 1512 RequestMethod.GET, 1513 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1514 ) 1515 assert isinstance(resp, dict) 1516 return resp 1517 1518 async def fetch_available_clan_fireteams( 1519 self, 1520 access_token: str, 1521 group_id: int, 1522 activity_type: fireteams.FireteamActivity | int, 1523 *, 1524 platform: fireteams.FireteamPlatform | int, 1525 language: fireteams.FireteamLanguage | str, 1526 date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL, 1527 page: int = 0, 1528 public_only: bool = False, 1529 slots_filter: int = 0, 1530 ) -> typedefs.JSONObject: 1531 resp = await self._request( 1532 RequestMethod.GET, 1533 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1534 json={"langFilter": str(language)}, 1535 auth=access_token, 1536 ) 1537 assert isinstance(resp, dict) 1538 return resp 1539 1540 async def fetch_clan_fireteam( 1541 self, access_token: str, fireteam_id: int, group_id: int 1542 ) -> typedefs.JSONObject: 1543 resp = await self._request( 1544 RequestMethod.GET, 1545 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1546 auth=access_token, 1547 ) 1548 assert isinstance(resp, dict) 1549 return resp 1550 1551 async def fetch_my_clan_fireteams( 1552 self, 1553 access_token: str, 1554 group_id: int, 1555 *, 1556 include_closed: bool = True, 1557 platform: fireteams.FireteamPlatform | int, 1558 language: fireteams.FireteamLanguage | str, 1559 filtered: bool = True, 1560 page: int = 0, 1561 ) -> typedefs.JSONObject: 1562 payload = {"groupFilter": filtered, "langFilter": str(language)} 1563 1564 resp = await self._request( 1565 RequestMethod.GET, 1566 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1567 json=payload, 1568 auth=access_token, 1569 ) 1570 assert isinstance(resp, dict) 1571 return resp 1572 1573 async def fetch_private_clan_fireteams( 1574 self, access_token: str, group_id: int, / 1575 ) -> int: 1576 resp = await self._request( 1577 RequestMethod.GET, 1578 f"Fireteam/Clan/{group_id}/ActiveCount", 1579 auth=access_token, 1580 ) 1581 assert isinstance(resp, int) 1582 return resp 1583 1584 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1585 resp = await self._request( 1586 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1587 ) 1588 assert isinstance(resp, dict) 1589 return resp 1590 1591 async def search_entities( 1592 self, name: str, entity_type: str, *, page: int = 0 1593 ) -> typedefs.JSONObject: 1594 resp = await self._request( 1595 RequestMethod.GET, 1596 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1597 json={"page": page}, 1598 ) 1599 assert isinstance(resp, dict) 1600 return resp 1601 1602 async def fetch_unique_weapon_history( 1603 self, 1604 membership_id: int, 1605 character_id: int, 1606 membership_type: enums.MembershipType | int, 1607 ) -> typedefs.JSONObject: 1608 resp = await self._request( 1609 RequestMethod.GET, 1610 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1611 ) 1612 assert isinstance(resp, dict) 1613 return resp 1614 1615 async def fetch_item( 1616 self, 1617 member_id: int, 1618 item_id: int, 1619 membership_type: enums.MembershipType | int, 1620 components: list[enums.ComponentType], 1621 ) -> typedefs.JSONObject: 1622 collector = _collect_components(components) 1623 1624 resp = await self._request( 1625 RequestMethod.GET, 1626 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1627 ) 1628 assert isinstance(resp, dict) 1629 return resp 1630 1631 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1632 resp = await self._request( 1633 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1634 ) 1635 assert isinstance(resp, dict) 1636 return resp 1637 1638 async def fetch_available_locales(self) -> typedefs.JSONObject: 1639 resp = await self._request( 1640 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1641 ) 1642 assert isinstance(resp, dict) 1643 return resp 1644 1645 async def fetch_common_settings(self) -> typedefs.JSONObject: 1646 resp = await self._request(RequestMethod.GET, "Settings") 1647 assert isinstance(resp, dict) 1648 return resp 1649 1650 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1651 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1652 assert isinstance(resp, dict) 1653 return resp 1654 1655 async def fetch_global_alerts( 1656 self, *, include_streaming: bool = False 1657 ) -> typedefs.JSONArray: 1658 resp = await self._request( 1659 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1660 ) 1661 assert isinstance(resp, list) 1662 return resp 1663 1664 async def awainitialize_request( 1665 self, 1666 access_token: str, 1667 type: typing.Literal[0, 1], 1668 membership_type: enums.MembershipType | int, 1669 /, 1670 *, 1671 affected_item_id: int | None = None, 1672 character_id: int | None = None, 1673 ) -> typedefs.JSONObject: 1674 body = {"type": type, "membershipType": int(membership_type)} 1675 1676 if affected_item_id is not None: 1677 body["affectedItemId"] = affected_item_id 1678 1679 if character_id is not None: 1680 body["characterId"] = character_id 1681 1682 resp = await self._request( 1683 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1684 ) 1685 assert isinstance(resp, dict) 1686 return resp 1687 1688 async def awaget_action_token( 1689 self, access_token: str, correlation_id: str, / 1690 ) -> typedefs.JSONObject: 1691 resp = await self._request( 1692 RequestMethod.POST, 1693 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1694 auth=access_token, 1695 ) 1696 assert isinstance(resp, dict) 1697 return resp 1698 1699 async def awa_provide_authorization_result( 1700 self, 1701 access_token: str, 1702 selection: int, 1703 correlation_id: str, 1704 nonce: collections.MutableSequence[str | bytes], 1705 ) -> int: 1706 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1707 1708 resp = await self._request( 1709 RequestMethod.POST, 1710 "Destiny2/Awa/AwaProvideAuthorizationResult", 1711 json=body, 1712 auth=access_token, 1713 ) 1714 assert isinstance(resp, int) 1715 return resp 1716 1717 async def fetch_vendors( 1718 self, 1719 access_token: str, 1720 character_id: int, 1721 membership_id: int, 1722 membership_type: enums.MembershipType | int, 1723 /, 1724 components: list[enums.ComponentType], 1725 filter: int | None = None, 1726 ) -> typedefs.JSONObject: 1727 components_ = _collect_components(components) 1728 route = ( 1729 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1730 f"/Character/{character_id}/Vendors/?components={components_}" 1731 ) 1732 1733 if filter is not None: 1734 route = route + f"&filter={filter}" 1735 1736 resp = await self._request( 1737 RequestMethod.GET, 1738 route, 1739 auth=access_token, 1740 ) 1741 assert isinstance(resp, dict) 1742 return resp 1743 1744 async def fetch_vendor( 1745 self, 1746 access_token: str, 1747 character_id: int, 1748 membership_id: int, 1749 membership_type: enums.MembershipType | int, 1750 vendor_hash: int, 1751 /, 1752 components: list[enums.ComponentType], 1753 ) -> typedefs.JSONObject: 1754 components_ = _collect_components(components) 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 ( 1758 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1759 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1760 ), 1761 auth=access_token, 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp 1765 1766 async def fetch_application_api_usage( 1767 self, 1768 access_token: str, 1769 application_id: int, 1770 /, 1771 *, 1772 start: datetime.datetime | None = None, 1773 end: datetime.datetime | None = None, 1774 ) -> typedefs.JSONObject: 1775 end_date, start_date = time.parse_date_range(end, start) 1776 resp = await self._request( 1777 RequestMethod.GET, 1778 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1779 auth=access_token, 1780 ) 1781 assert isinstance(resp, dict) 1782 return resp 1783 1784 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1785 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1786 assert isinstance(resp, list) 1787 return resp 1788 1789 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1790 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1791 assert isinstance(resp, dict) 1792 return resp 1793 1794 async def fetch_content_by_id( 1795 self, id: int, locale: str, /, *, head: bool = False 1796 ) -> typedefs.JSONObject: 1797 resp = await self._request( 1798 RequestMethod.GET, 1799 f"Content/GetContentById/{id}/{locale}/", 1800 json={"head": head}, 1801 ) 1802 assert isinstance(resp, dict) 1803 return resp 1804 1805 async def fetch_content_by_tag_and_type( 1806 self, locale: str, tag: str, type: str, *, head: bool = False 1807 ) -> typedefs.JSONObject: 1808 resp = await self._request( 1809 RequestMethod.GET, 1810 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1811 json={"head": head}, 1812 ) 1813 assert isinstance(resp, dict) 1814 return resp 1815 1816 async def search_content_with_text( 1817 self, 1818 locale: str, 1819 /, 1820 content_type: str, 1821 search_text: str, 1822 tag: str, 1823 *, 1824 page: int | None = None, 1825 source: str | None = None, 1826 ) -> typedefs.JSONObject: 1827 body: typedefs.JSONObject = { 1828 "locale": locale, 1829 "currentpage": page or 1, 1830 "ctype": content_type, 1831 "searchtxt": search_text, 1832 "ctype": content_type, 1833 "searchtext": search_text, 1834 "tag": tag, 1835 "source": source, 1836 } 1837 1838 resp = await self._request(RequestMethod.GET, "Content/Search", params=body) 1839 assert isinstance(resp, dict) 1840 return resp 1841 1842 async def search_content_by_tag_and_type( 1843 self, 1844 locale: str, 1845 tag: str, 1846 type: str, 1847 *, 1848 page: int | None = None, 1849 ) -> typedefs.JSONObject: 1850 body: typedefs.JSONObject = {"currentpage": page or 1} 1851 1852 resp = await self._request( 1853 RequestMethod.GET, 1854 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 1855 params=body, 1856 ) 1857 assert isinstance(resp, dict) 1858 return resp 1859 1860 async def search_help_articles( 1861 self, text: str, size: str, / 1862 ) -> typedefs.JSONObject: 1863 resp = await self._request( 1864 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 1865 ) 1866 assert isinstance(resp, dict) 1867 return resp 1868 1869 async def fetch_topics_page( 1870 self, 1871 category_filter: int, 1872 group: int, 1873 date_filter: int, 1874 sort: str | bytes, 1875 *, 1876 page: int | None = None, 1877 locales: collections.Iterable[str] | None = None, 1878 tag_filter: str | None = None, 1879 ) -> typedefs.JSONObject: 1880 params = { 1881 "locales": ",".join(locales) if locales is not None else "en", 1882 } 1883 if tag_filter: 1884 params["tagstring"] = tag_filter 1885 1886 resp = await self._request( 1887 RequestMethod.GET, 1888 f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/", 1889 params=params, 1890 ) 1891 assert isinstance(resp, dict) 1892 return resp 1893 1894 async def fetch_core_topics_page( 1895 self, 1896 category_filter: int, 1897 date_filter: int, 1898 sort: str | bytes, 1899 *, 1900 page: int | None = None, 1901 locales: collections.Iterable[str] | None = None, 1902 ) -> typedefs.JSONObject: 1903 resp = await self._request( 1904 RequestMethod.GET, 1905 f"Forum/GetCoreTopicsPaged/{page or 0}" 1906 f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}", 1907 ) 1908 assert isinstance(resp, dict) 1909 return resp 1910 1911 async def fetch_posts_threaded_page( 1912 self, 1913 parent_post: bool, 1914 page: int, 1915 page_size: int, 1916 parent_post_id: int, 1917 reply_size: int, 1918 root_thread_mode: bool, 1919 sort_mode: int, 1920 show_banned: str | None = None, 1921 ) -> typedefs.JSONObject: 1922 resp = await self._request( 1923 RequestMethod.GET, 1924 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 1925 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 1926 json={"showbanned": show_banned}, 1927 ) 1928 assert isinstance(resp, dict) 1929 return resp 1930 1931 async def fetch_posts_threaded_page_from_child( 1932 self, 1933 child_id: bool, 1934 page: int, 1935 page_size: int, 1936 reply_size: int, 1937 root_thread_mode: bool, 1938 sort_mode: int, 1939 show_banned: str | None = None, 1940 ) -> typedefs.JSONObject: 1941 resp = await self._request( 1942 RequestMethod.GET, 1943 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 1944 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 1945 json={"showbanned": show_banned}, 1946 ) 1947 assert isinstance(resp, dict) 1948 return resp 1949 1950 async def fetch_post_and_parent( 1951 self, child_id: int, /, *, show_banned: str | None = None 1952 ) -> typedefs.JSONObject: 1953 resp = await self._request( 1954 RequestMethod.GET, 1955 f"Forum/GetPostAndParent/{child_id}/", 1956 json={"showbanned": show_banned}, 1957 ) 1958 assert isinstance(resp, dict) 1959 return resp 1960 1961 async def fetch_posts_and_parent_awaiting( 1962 self, child_id: int, /, *, show_banned: str | None = None 1963 ) -> typedefs.JSONObject: 1964 resp = await self._request( 1965 RequestMethod.GET, 1966 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 1967 json={"showbanned": show_banned}, 1968 ) 1969 assert isinstance(resp, dict) 1970 return resp 1971 1972 async def fetch_topic_for_content(self, content_id: int, /) -> int: 1973 resp = await self._request( 1974 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 1975 ) 1976 assert isinstance(resp, int) 1977 return resp 1978 1979 async def fetch_forum_tag_suggestions( 1980 self, partial_tag: str, / 1981 ) -> typedefs.JSONObject: 1982 resp = await self._request( 1983 RequestMethod.GET, 1984 "Forum/GetForumTagSuggestions/", 1985 json={"partialtag": partial_tag}, 1986 ) 1987 assert isinstance(resp, dict) 1988 return resp 1989 1990 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 1991 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 1992 assert isinstance(resp, dict) 1993 return resp 1994 1995 async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray: 1996 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 1997 assert isinstance(resp, list) 1998 return resp 1999 2000 async def fetch_recommended_groups( 2001 self, 2002 access_token: str, 2003 /, 2004 *, 2005 date_range: int = 0, 2006 group_type: enums.GroupType | int = enums.GroupType.CLAN, 2007 ) -> typedefs.JSONArray: 2008 resp = await self._request( 2009 RequestMethod.POST, 2010 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2011 auth=access_token, 2012 ) 2013 assert isinstance(resp, list) 2014 return resp 2015 2016 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2017 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2018 assert isinstance(resp, dict) 2019 return resp 2020 2021 async def fetch_user_clan_invite_setting( 2022 self, 2023 access_token: str, 2024 /, 2025 membership_type: enums.MembershipType | int, 2026 ) -> bool: 2027 resp = await self._request( 2028 RequestMethod.GET, 2029 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2030 auth=access_token, 2031 ) 2032 assert isinstance(resp, bool) 2033 return resp 2034 2035 async def fetch_banned_group_members( 2036 self, access_token: str, group_id: int, /, *, page: int = 1 2037 ) -> typedefs.JSONObject: 2038 resp = await self._request( 2039 RequestMethod.GET, 2040 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2041 auth=access_token, 2042 ) 2043 assert isinstance(resp, dict) 2044 return resp 2045 2046 async def fetch_pending_group_memberships( 2047 self, access_token: str, group_id: int, /, *, current_page: int = 1 2048 ) -> typedefs.JSONObject: 2049 resp = await self._request( 2050 RequestMethod.GET, 2051 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2052 auth=access_token, 2053 ) 2054 assert isinstance(resp, dict) 2055 return resp 2056 2057 async def fetch_invited_group_memberships( 2058 self, access_token: str, group_id: int, /, *, current_page: int = 1 2059 ) -> typedefs.JSONObject: 2060 resp = await self._request( 2061 RequestMethod.GET, 2062 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2063 auth=access_token, 2064 ) 2065 assert isinstance(resp, dict) 2066 return resp 2067 2068 async def invite_member_to_group( 2069 self, 2070 access_token: str, 2071 /, 2072 group_id: int, 2073 membership_id: int, 2074 membership_type: enums.MembershipType | int, 2075 *, 2076 message: str | None = None, 2077 ) -> typedefs.JSONObject: 2078 resp = await self._request( 2079 RequestMethod.POST, 2080 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2081 auth=access_token, 2082 json={"message": str(message)}, 2083 ) 2084 assert isinstance(resp, dict) 2085 return resp 2086 2087 async def cancel_group_member_invite( 2088 self, 2089 access_token: str, 2090 /, 2091 group_id: int, 2092 membership_id: int, 2093 membership_type: enums.MembershipType | int, 2094 ) -> typedefs.JSONObject: 2095 resp = await self._request( 2096 RequestMethod.POST, 2097 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2098 auth=access_token, 2099 ) 2100 assert isinstance(resp, dict) 2101 return resp 2102 2103 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2104 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2105 assert isinstance(resp, dict) 2106 return resp 2107 2108 async def fetch_historical_stats( 2109 self, 2110 character_id: int, 2111 membership_id: int, 2112 membership_type: enums.MembershipType | int, 2113 day_start: datetime.datetime, 2114 day_end: datetime.datetime, 2115 groups: list[enums.StatsGroupType | int], 2116 modes: collections.Sequence[enums.GameMode | int], 2117 *, 2118 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2119 ) -> typedefs.JSONObject: 2120 end, start = time.parse_date_range(day_end, day_start) 2121 resp = await self._request( 2122 RequestMethod.GET, 2123 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2124 json={ 2125 "dayend": end, 2126 "daystart": start, 2127 "groups": [str(int(group)) for group in groups], 2128 "modes": [str(int(mode)) for mode in modes], 2129 "periodType": int(period_type), 2130 }, 2131 ) 2132 assert isinstance(resp, dict) 2133 return resp 2134 2135 async def fetch_historical_stats_for_account( 2136 self, 2137 membership_id: int, 2138 membership_type: enums.MembershipType | int, 2139 groups: list[enums.StatsGroupType | int], 2140 ) -> typedefs.JSONObject: 2141 resp = await self._request( 2142 RequestMethod.GET, 2143 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2144 json={"groups": [str(int(group)) for group in groups]}, 2145 ) 2146 assert isinstance(resp, dict) 2147 return resp 2148 2149 async def fetch_aggregated_activity_stats( 2150 self, 2151 character_id: int, 2152 membership_id: int, 2153 membership_type: enums.MembershipType | int, 2154 /, 2155 ) -> typedefs.JSONObject: 2156 resp = await self._request( 2157 RequestMethod.GET, 2158 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2159 f"Character/{character_id}/Stats/AggregateActivityStats/", 2160 ) 2161 assert isinstance(resp, dict) 2162 return resp 2163 2164 async def equip_loadout( 2165 self, 2166 access_token: str, 2167 /, 2168 loadout_index: int, 2169 character_id: int, 2170 membership_type: enums.MembershipType | int, 2171 ) -> None: 2172 response = await self._request( 2173 RequestMethod.POST, 2174 "Destiny2/Actions/Loadouts/EquipLoadout/", 2175 json={ 2176 "loadoutIndex": loadout_index, 2177 "characterId": character_id, 2178 "membership_type": int(membership_type), 2179 }, 2180 auth=access_token, 2181 ) 2182 assert isinstance(response, int) 2183 2184 async def snapshot_loadout( 2185 self, 2186 access_token: str, 2187 /, 2188 loadout_index: int, 2189 character_id: int, 2190 membership_type: enums.MembershipType | int, 2191 *, 2192 color_hash: int | None = None, 2193 icon_hash: int | None = None, 2194 name_hash: int | None = None, 2195 ) -> None: 2196 response = await self._request( 2197 RequestMethod.POST, 2198 "Destiny2/Actions/Loadouts/SnapshotLoadout/", 2199 auth=access_token, 2200 json={ 2201 "colorHash": color_hash, 2202 "iconHash": icon_hash, 2203 "nameHash": name_hash, 2204 "loadoutIndex": loadout_index, 2205 "characterId": character_id, 2206 "membershipType": int(membership_type), 2207 }, 2208 ) 2209 assert isinstance(response, int) 2210 2211 async def update_loadout( 2212 self, 2213 access_token: str, 2214 /, 2215 loadout_index: int, 2216 character_id: int, 2217 membership_type: enums.MembershipType | int, 2218 *, 2219 color_hash: int | None = None, 2220 icon_hash: int | None = None, 2221 name_hash: int | None = None, 2222 ) -> None: 2223 response = await self._request( 2224 RequestMethod.POST, 2225 "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/", 2226 auth=access_token, 2227 json={ 2228 "colorHash": color_hash, 2229 "iconHash": icon_hash, 2230 "nameHash": name_hash, 2231 "loadoutIndex": loadout_index, 2232 "characterId": character_id, 2233 "membershipType": int(membership_type), 2234 }, 2235 ) 2236 assert isinstance(response, int) 2237 2238 async def clear_loadout( 2239 self, 2240 access_token: str, 2241 /, 2242 loadout_index: int, 2243 character_id: int, 2244 membership_type: enums.MembershipType | int, 2245 ) -> None: 2246 response = await self._request( 2247 RequestMethod.POST, 2248 "Destiny2/Actions/Loadouts/ClearLoadout/", 2249 json={ 2250 "loadoutIndex": loadout_index, 2251 "characterId": character_id, 2252 "membership_type": int(membership_type), 2253 }, 2254 auth=access_token, 2255 ) 2256 assert isinstance(response, int)
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is the core for aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
client = aiobungie.RESTClient("TOKEN")
async with client:
response = await client.fetch_clan_members(4389205)
for member in response['results']:
for key, value in member['destinyUserInfo'].items():
print(key, value)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | TRACE: This will log the response headers along with the minimal information.
364 def __init__( 365 self, 366 token: str, 367 /, 368 *, 369 client_secret: str | None = None, 370 client_id: int | None = None, 371 client_session: aiohttp.ClientSession | None = None, 372 dumps: typedefs.Dumps = helpers.dumps, 373 loads: typedefs.Loads = helpers.loads, 374 max_retries: int = 4, 375 enable_debugging: typing.Literal["TRACE"] | bool | int = False, 376 ) -> None: 377 self._session = client_session 378 self._lock: asyncio.Lock | None = None 379 self._client_secret = client_secret 380 self._client_id = client_id 381 self._token: str = token 382 self._max_retries = max_retries 383 self._dumps = dumps 384 self._loads = loads 385 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 386 387 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
401 @typing.final 402 async def close(self) -> None: 403 if self._session is None: 404 raise RuntimeError("REST client is not running.") 405 406 await self._session.close() 407 self._session = None
Close this REST client session if it was acquired.
This method is automatically called when using async with contextmanager.
Raises
RuntimeError: If the client is already closed.
409 @typing.final 410 def open(self) -> None: 411 """Open a new client session. This is called internally with contextmanager usage.""" 412 if self._session: 413 raise RuntimeError("Cannot open REST client when it's already open.") 414 415 self._session = aiohttp.ClientSession( 416 connector=aiohttp.TCPConnector(), 417 connector_owner=True, 418 raise_for_status=False, 419 timeout=aiohttp.ClientTimeout(total=30.0), 420 )
Open a new client session. This is called internally with contextmanager usage.
422 @typing.final 423 def enable_debugging( 424 self, 425 level: typing.Literal["TRACE"] | bool | int = False, 426 file: pathlib.Path | str | None = None, 427 /, 428 ) -> None: 429 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
431 @typing.final 432 async def static_request( 433 self, 434 method: RequestMethod | str, 435 path: str, 436 *, 437 auth: str | None = None, 438 json: collections.Mapping[str, typing.Any] | None = None, 439 ) -> typedefs.JSONIsh: 440 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/...
Other Parameters
- auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
MutableMapping[str, typing.Any] | None): An optional JSON mapping to include in the request.
Returns
aiobungie.typedefs.JSONIsh: The response payload.
442 @typing.final 443 def build_oauth2_url( 444 self, client_id: int | None = None 445 ) -> builders.OAuthURL | None: 446 client_id = client_id or self._client_id 447 if client_id is None: 448 return None 449 450 return builders.OAuthURL(client_id=client_id)
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
You can't get the complete string URL by using .compile() method.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
aiobungie.builders.OAuthURL | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete OAuthURL object will be returned. OtherwiseNonewill be returned.
641 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 642 if not isinstance(self._client_secret, (str, int)): 643 raise TypeError( 644 "Expected (str, int) for client secret " 645 f"but got {type(self._client_secret).__name__}" # type: ignore 646 ) 647 648 headers = { 649 "client_secret": self._client_secret, 650 } 651 652 data = ( 653 f"grant_type=authorization_code&code={code}" 654 f"&client_id={self._client_id}&client_secret={self._client_secret}" 655 ) 656 657 response = await self._request( 658 RequestMethod.POST, "", headers=headers, json=data, oauth2=True 659 ) 660 assert isinstance(response, dict) 661 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
Unauthorized: The passed code was invalid.
663 async def refresh_access_token( 664 self, refresh_token: str, / 665 ) -> builders.OAuth2Response: 666 if not isinstance(self._client_secret, (int, str)): 667 raise TypeError( 668 f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}" # type: ignore 669 ) 670 671 data = { 672 "grant_type": "refresh_token", 673 "refresh_token": refresh_token, 674 "client_id": self._client_id, 675 "client_secret": self._client_secret, 676 "Content-Type": "application/x-www-form-urlencoded", 677 } 678 679 response = await self._request(RequestMethod.POST, "", json=data, oauth2=True) 680 assert isinstance(response, dict) 681 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
683 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 684 resp = await self._request( 685 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 686 ) 687 assert isinstance(resp, dict) 688 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
NotFound: The user was not found.
695 async def fetch_membership_from_id( 696 self, 697 id: int, 698 type: enums.MembershipType | int = enums.MembershipType.NONE, 699 /, 700 ) -> typedefs.JSONObject: 701 resp = await self._request( 702 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 703 ) 704 assert isinstance(resp, dict) 705 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.aiobungie.MembershipType | int): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
707 async def fetch_membership( 708 self, 709 name: str, 710 code: int, 711 type: enums.MembershipType | int = enums.MembershipType.ALL, 712 /, 713 ) -> typedefs.JSONArray: 714 resp = await self._request( 715 RequestMethod.POST, 716 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 717 json={"displayName": name, "displayNameCode": code}, 718 ) 719 assert isinstance(resp, list) 720 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.aiobungie.MembershipType | int): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
722 async def search_users(self, name: str, /) -> typedefs.JSONObject: 723 resp = await self._request( 724 RequestMethod.POST, 725 "User/Search/GlobalName/0", 726 json={"displayNamePrefix": name}, 727 ) 728 assert isinstance(resp, dict) 729 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
731 async def fetch_clan_from_id( 732 self, id: int, /, access_token: str | None = None 733 ) -> typedefs.JSONObject: 734 resp = await self._request( 735 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 736 ) 737 assert isinstance(resp, dict) 738 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
str | None): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
740 async def fetch_clan( 741 self, 742 name: str, 743 /, 744 access_token: str | None = None, 745 *, 746 type: enums.GroupType | int = enums.GroupType.CLAN, 747 ) -> typedefs.JSONObject: 748 resp = await self._request( 749 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 750 ) 751 assert isinstance(resp, dict) 752 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
str | None): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.aiobungie.GroupType | int): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
754 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 755 resp = await self._request( 756 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 757 ) 758 assert isinstance(resp, dict) 759 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
761 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 762 resp = await self._request( 763 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 764 ) 765 assert isinstance(resp, list) 766 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
768 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 769 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 770 assert isinstance(resp, dict) 771 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
773 async def fetch_character( 774 self, 775 member_id: int, 776 membership_type: enums.MembershipType | int, 777 character_id: int, 778 components: list[enums.ComponentType], 779 auth: str | None = None, 780 ) -> typedefs.JSONObject: 781 collector = _collect_components(components) 782 response = await self._request( 783 RequestMethod.GET, 784 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 785 f"Character/{character_id}/?components={collector}", 786 auth=auth, 787 ) 788 assert isinstance(response, dict) 789 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.aiobungie.internal.enums.MembershipType | int): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
791 async def fetch_activities( 792 self, 793 member_id: int, 794 character_id: int, 795 mode: enums.GameMode | int, 796 membership_type: enums.MembershipType | int = enums.MembershipType.ALL, 797 *, 798 page: int = 0, 799 limit: int = 1, 800 ) -> typedefs.JSONObject: 801 resp = await self._request( 802 RequestMethod.GET, 803 f"Destiny2/{int(membership_type)}/Account/" 804 f"{member_id}/Character/{character_id}/Stats/Activities" 805 f"/?mode={int(mode)}&count={limit}&page={page}", 806 ) 807 assert isinstance(resp, dict) 808 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.aiobungie.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.aiobungie.internal.enums.MembershipType | int): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
818 async def fetch_profile( 819 self, 820 membership_id: int, 821 type: enums.MembershipType | int, 822 components: list[enums.ComponentType], 823 auth: str | None = None, 824 ) -> typedefs.JSONObject: 825 collector = _collect_components(components) 826 response = await self._request( 827 RequestMethod.GET, 828 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 829 auth=auth, 830 ) 831 assert isinstance(response, dict) 832 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.aiobungie.MembershipType | int): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
834 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 835 response = await self._request( 836 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 837 ) 838 assert isinstance(response, dict) 839 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
841 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 842 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 843 assert isinstance(resp, dict) 844 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
846 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 847 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 848 assert isinstance(resp, dict) 849 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objective data.
851 async def fetch_groups_for_member( 852 self, 853 member_id: int, 854 member_type: enums.MembershipType | int, 855 /, 856 *, 857 filter: int = 0, 858 group_type: enums.GroupType | int = enums.GroupType.CLAN, 859 ) -> typedefs.JSONObject: 860 resp = await self._request( 861 RequestMethod.GET, 862 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 863 ) 864 assert isinstance(resp, dict) 865 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.aiobungie.GroupType | int): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
867 async def fetch_potential_groups_for_member( 868 self, 869 member_id: int, 870 member_type: enums.MembershipType | int, 871 /, 872 *, 873 filter: int = 0, 874 group_type: enums.GroupType | int = enums.GroupType.CLAN, 875 ) -> typedefs.JSONObject: 876 resp = await self._request( 877 RequestMethod.GET, 878 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 879 ) 880 assert isinstance(resp, dict) 881 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.aiobungie.GroupType | int): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
883 async def fetch_clan_members( 884 self, 885 clan_id: int, 886 /, 887 *, 888 name: str | None = None, 889 type: enums.MembershipType | int = enums.MembershipType.NONE, 890 ) -> typedefs.JSONObject: 891 resp = await self._request( 892 RequestMethod.GET, 893 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 894 ) 895 assert isinstance(resp, dict) 896 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
str | None): If provided, Only players matching this name will be returned. - type (
aiobungie.aiobungie.MembershipType | int): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
898 async def fetch_hardlinked_credentials( 899 self, 900 credential: int, 901 type: enums.CredentialType | int = enums.CredentialType.STEAMID, 902 /, 903 ) -> typedefs.JSONObject: 904 resp = await self._request( 905 RequestMethod.GET, 906 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 907 ) 908 assert isinstance(resp, dict) 909 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.aiobungie.CredentialType | int): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
911 async def fetch_user_credentials( 912 self, access_token: str, membership_id: int, / 913 ) -> typedefs.JSONArray: 914 resp = await self._request( 915 RequestMethod.GET, 916 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 917 auth=access_token, 918 ) 919 assert isinstance(resp, list) 920 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
922 async def insert_socket_plug( 923 self, 924 action_token: str, 925 /, 926 instance_id: int, 927 plug: builders.PlugSocketBuilder | collections.Mapping[str, int], 928 character_id: int, 929 membership_type: enums.MembershipType | int, 930 ) -> typedefs.JSONObject: 931 if isinstance(plug, builders.PlugSocketBuilder): 932 plug = plug.collect() 933 934 body = { 935 "actionToken": action_token, 936 "itemInstanceId": instance_id, 937 "plug": plug, 938 "characterId": character_id, 939 "membershipType": int(membership_type), 940 } 941 resp = await self._request( 942 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 943 ) 944 assert isinstance(resp, dict) 945 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.aiobungie.MembershipType | int
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
947 async def insert_socket_plug_free( 948 self, 949 access_token: str, 950 /, 951 instance_id: int, 952 plug: builders.PlugSocketBuilder | collections.Mapping[str, int], 953 character_id: int, 954 membership_type: enums.MembershipType | int, 955 ) -> typedefs.JSONObject: 956 if isinstance(plug, builders.PlugSocketBuilder): 957 plug = plug.collect() 958 959 body = { 960 "itemInstanceId": instance_id, 961 "plug": plug, 962 "characterId": character_id, 963 "membershipType": int(membership_type), 964 } 965 resp = await self._request( 966 RequestMethod.POST, 967 "Destiny2/Actions/Items/InsertSocketPlugFree", 968 json=body, 969 auth=access_token, 970 ) 971 assert isinstance(resp, dict) 972 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.aiobungie.MembershipType | int
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
974 async def set_item_lock_state( 975 self, 976 access_token: str, 977 state: bool, 978 /, 979 item_id: int, 980 character_id: int, 981 membership_type: enums.MembershipType | int, 982 ) -> int: 983 body = { 984 "state": state, 985 "itemId": item_id, 986 "characterId": character_id, 987 "membershipType": int(membership_type), 988 } 989 response = await self._request( 990 RequestMethod.POST, 991 "Destiny2/Actions/Items/SetLockState", 992 json=body, 993 auth=access_token, 994 ) 995 assert isinstance(response, int) 996 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
998 async def set_quest_track_state( 999 self, 1000 access_token: str, 1001 state: bool, 1002 /, 1003 item_id: int, 1004 character_id: int, 1005 membership_type: enums.MembershipType | int, 1006 ) -> int: 1007 body = { 1008 "state": state, 1009 "itemId": item_id, 1010 "characterId": character_id, 1011 "membership_type": int(membership_type), 1012 } 1013 response = await self._request( 1014 RequestMethod.POST, 1015 "Destiny2/Actions/Items/SetTrackedState", 1016 json=body, 1017 auth=access_token, 1018 ) 1019 assert isinstance(response, int) 1020 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1022 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1023 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1024 assert isinstance(path, dict) 1025 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1027 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1028 _ensure_manifest_language(language) 1029 1030 content = await self.fetch_manifest_path() 1031 resp = await self._request( 1032 RequestMethod.GET, 1033 content["mobileWorldContentPaths"][language], 1034 unwrapping="read", 1035 base=True, 1036 ) 1037 assert isinstance(resp, bytes) 1038 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1040 async def download_sqlite_manifest( 1041 self, 1042 language: str = "en", 1043 name: str = "manifest", 1044 path: pathlib.Path | str = ".", 1045 *, 1046 force: bool = False, 1047 ) -> pathlib.Path: 1048 complete_path = _get_path(name, path, sql=True) 1049 1050 if complete_path.exists() and force: 1051 if force: 1052 _LOG.info( 1053 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1054 ) 1055 complete_path.unlink(missing_ok=True) 1056 1057 return await self.download_sqlite_manifest( 1058 language, name, path, force=force 1059 ) 1060 1061 else: 1062 raise FileExistsError( 1063 "Manifest file already exists, " 1064 "To force download, set the `force` parameter to `True`." 1065 ) 1066 1067 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1068 data_bytes = await self.read_manifest_bytes(language) 1069 await asyncio.get_running_loop().run_in_executor( 1070 None, _write_sqlite_bytes, data_bytes, path, name 1071 ) 1072 return _get_path(name, path, sql=True)
Downloads the SQLite version of Destiny2's Manifest.
Example
manifest = await rest.download_sqlite_manifest()
with sqlite3.connect(manifest) as conn:
...
Parameters
- language (
str): The manifest language to download, Default is English. - path (
str|pathlib.Path): The path to download this manifest. Example"/tmp/databases/", Default is the current directory. - name (
str): The manifest database file name. Default ismanifest - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get unlinked and a new one will begin to download.
Returns
pathlib.Path: A pathlib object of the.sqlitefile.
Raises
FileNotFoundError: If the manifest file exists andforceisFalse.ValueError: If the provided language was not recognized.
1074 async def download_json_manifest( 1075 self, 1076 file_name: str = "manifest", 1077 path: str | pathlib.Path = ".", 1078 language: str = "en", 1079 ) -> pathlib.Path: 1080 _ensure_manifest_language(language) 1081 1082 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1083 1084 content = await self.fetch_manifest_path() 1085 json_bytes = await self._request( 1086 RequestMethod.GET, 1087 content["jsonWorldContentPaths"][language], 1088 unwrapping="read", 1089 base=True, 1090 ) 1091 1092 await asyncio.get_running_loop().run_in_executor( 1093 None, _write_json_bytes, json_bytes, file_name, path 1094 ) 1095 _LOG.info("Finished downloading manifest JSON.") 1096 return _get_path(file_name, path)
Download the Bungie manifest json file.
Example
manifest = await rest.download_json_manifest()
with open(manifest, "r") as f:
to_dict = json.loads(f.read())
item_definitions = to_dict['DestinyInventoryItemDefinition']
Parameters
- file_name (
str): The file name to save the manifest json file. Default ismanifest. - path (
str|pathlib.Path): The path to save the manifest json file. Default is the current directory. Example"D:/" - language (
str): The manifest database language bytes to get. Default is English.
Returns
pathlib.Path: The path of this JSON manifest.
1098 async def fetch_manifest_version(self) -> str: 1099 # This is guaranteed str. 1100 return (await self.fetch_manifest_path())["version"] # type: ignore[no-any-return]
Fetch the manifest version.
Returns
str: The manifest version.
1102 async def fetch_linked_profiles( 1103 self, 1104 member_id: int, 1105 member_type: enums.MembershipType | int, 1106 /, 1107 *, 1108 all: bool = False, 1109 ) -> typedefs.JSONObject: 1110 resp = await self._request( 1111 RequestMethod.GET, 1112 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1113 ) 1114 assert isinstance(resp, dict) 1115 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.aiobungie.MembershipType | int): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1124 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1125 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1126 assert isinstance(resp, dict) 1127 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1129 async def fetch_public_milestone_content( 1130 self, milestone_hash: int, / 1131 ) -> typedefs.JSONObject: 1132 resp = await self._request( 1133 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1134 ) 1135 assert isinstance(resp, dict) 1136 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1138 async def fetch_current_user_memberships( 1139 self, access_token: str, / 1140 ) -> typedefs.JSONObject: 1141 resp = await self._request( 1142 RequestMethod.GET, 1143 "User/GetMembershipsForCurrentUser/", 1144 auth=access_token, 1145 ) 1146 assert isinstance(resp, dict) 1147 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1149 async def equip_item( 1150 self, 1151 access_token: str, 1152 /, 1153 item_id: int, 1154 character_id: int, 1155 membership_type: enums.MembershipType | int, 1156 ) -> None: 1157 payload = { 1158 "itemId": item_id, 1159 "characterId": character_id, 1160 "membershipType": int(membership_type), 1161 } 1162 1163 await self._request( 1164 RequestMethod.POST, 1165 "Destiny2/Actions/Items/EquipItem/", 1166 json=payload, 1167 auth=access_token, 1168 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
1170 async def equip_items( 1171 self, 1172 access_token: str, 1173 /, 1174 item_ids: collections.Sequence[int], 1175 character_id: int, 1176 membership_type: enums.MembershipType | int, 1177 ) -> None: 1178 payload = { 1179 "itemIds": item_ids, 1180 "characterId": character_id, 1181 "membershipType": int(membership_type), 1182 } 1183 await self._request( 1184 RequestMethod.POST, 1185 "Destiny2/Actions/Items/EquipItems/", 1186 json=payload, 1187 auth=access_token, 1188 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
Sequence[int]): A sequence of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
1190 async def ban_clan_member( 1191 self, 1192 access_token: str, 1193 /, 1194 group_id: int, 1195 membership_id: int, 1196 membership_type: enums.MembershipType | int, 1197 *, 1198 length: int = 0, 1199 comment: str | None = None, 1200 ) -> None: 1201 payload = {"comment": str(comment), "length": length} 1202 await self._request( 1203 RequestMethod.POST, 1204 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1205 json=payload, 1206 auth=access_token, 1207 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1209 async def unban_clan_member( 1210 self, 1211 access_token: str, 1212 /, 1213 group_id: int, 1214 membership_id: int, 1215 membership_type: enums.MembershipType | int, 1216 ) -> None: 1217 await self._request( 1218 RequestMethod.POST, 1219 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1220 auth=access_token, 1221 )
Unban a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
1223 async def kick_clan_member( 1224 self, 1225 access_token: str, 1226 /, 1227 group_id: int, 1228 membership_id: int, 1229 membership_type: enums.MembershipType | int, 1230 ) -> typedefs.JSONObject: 1231 resp = await self._request( 1232 RequestMethod.POST, 1233 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1234 auth=access_token, 1235 ) 1236 assert isinstance(resp, dict) 1237 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1239 async def edit_clan( 1240 self, 1241 access_token: str, 1242 /, 1243 group_id: int, 1244 *, 1245 name: str | None = None, 1246 about: str | None = None, 1247 motto: str | None = None, 1248 theme: str | None = None, 1249 tags: collections.Sequence[str] | None = None, 1250 is_public: bool | None = None, 1251 locale: str | None = None, 1252 avatar_image_index: int | None = None, 1253 membership_option: enums.MembershipOption | int | None = None, 1254 allow_chat: bool | None = None, 1255 chat_security: typing.Literal[0, 1] | None = None, 1256 call_sign: str | None = None, 1257 homepage: typing.Literal[0, 1, 2] | None = None, 1258 enable_invite_messaging_for_admins: bool | None = None, 1259 default_publicity: typing.Literal[0, 1, 2] | None = None, 1260 is_public_topic_admin: bool | None = None, 1261 ) -> None: 1262 payload = { 1263 "name": name, 1264 "about": about, 1265 "motto": motto, 1266 "theme": theme, 1267 "tags": tags, 1268 "isPublic": is_public, 1269 "avatarImageIndex": avatar_image_index, 1270 "isPublicTopicAdminOnly": is_public_topic_admin, 1271 "allowChat": allow_chat, 1272 "chatSecurity": chat_security, 1273 "callsign": call_sign, 1274 "homepage": homepage, 1275 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1276 "defaultPublicity": default_publicity, 1277 "locale": locale, 1278 } 1279 if membership_option is not None: 1280 payload["membershipOption"] = int(membership_option) 1281 1282 await self._request( 1283 RequestMethod.POST, 1284 f"GroupV2/{group_id}/Edit", 1285 json=payload, 1286 auth=access_token, 1287 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
str | None): The name to edit the clan with. - about (
str | None): The about section to edit the clan with. - motto (
str | None): The motto section to edit the clan with. - theme (
str | None): The theme name to edit the clan with. - tags (
collections.Sequence[str] | None): A sequence of strings to replace the clan tags with. - is_public (
bool | None): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
str | None): The locale section to edit the clan with. - avatar_image_index (
int | None): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.aiobungie.MembershipOption | int]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
bool | None): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
str | None): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
bool | None): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
bool | None): ???
1289 async def edit_clan_options( 1290 self, 1291 access_token: str, 1292 /, 1293 group_id: int, 1294 *, 1295 invite_permissions_override: bool | None = None, 1296 update_culture_permissionOverride: bool | None = None, 1297 host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None, 1298 update_banner_permission_override: bool | None = None, 1299 join_level: enums.ClanMemberType | int | None = None, 1300 ) -> None: 1301 payload = { 1302 "InvitePermissionOverride": invite_permissions_override, 1303 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1304 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1305 "UpdateBannerPermissionOverride": update_banner_permission_override, 1306 "JoinLevel": int(join_level) if join_level else None, 1307 } 1308 1309 await self._request( 1310 RequestMethod.POST, 1311 f"GroupV2/{group_id}/EditFounderOptions", 1312 json=payload, 1313 auth=access_token, 1314 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
bool | None): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
bool | None): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
bool | None): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1316 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1317 resp = await self._request( 1318 RequestMethod.GET, 1319 "Social/Friends/", 1320 auth=access_token, 1321 ) 1322 assert isinstance(resp, dict) 1323 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1325 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1326 resp = await self._request( 1327 RequestMethod.GET, 1328 "Social/Friends/Requests", 1329 auth=access_token, 1330 ) 1331 assert isinstance(resp, dict) 1332 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1334 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1335 await self._request( 1336 RequestMethod.POST, 1337 f"Social/Friends/Requests/Accept/{member_id}", 1338 auth=access_token, 1339 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1341 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1342 await self._request( 1343 RequestMethod.POST, 1344 f"Social/Friends/Add/{member_id}", 1345 auth=access_token, 1346 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1348 async def decline_friend_request( 1349 self, access_token: str, /, member_id: int 1350 ) -> None: 1351 await self._request( 1352 RequestMethod.POST, 1353 f"Social/Friends/Requests/Decline/{member_id}", 1354 auth=access_token, 1355 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1357 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1358 await self._request( 1359 RequestMethod.POST, 1360 f"Social/Friends/Remove/{member_id}", 1361 auth=access_token, 1362 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1364 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1365 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1366 await self._request( 1367 RequestMethod.POST, 1368 f"Social/Friends/Requests/Remove/{member_id}", 1369 auth=access_token, 1370 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1372 async def approve_all_pending_group_users( 1373 self, 1374 access_token: str, 1375 /, 1376 group_id: int, 1377 message: str | None = None, 1378 ) -> None: 1379 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1380 await self._request( 1381 RequestMethod.POST, 1382 f"GroupV2/{group_id}/Members/ApproveAll", 1383 auth=access_token, 1384 json={"message": str(message)}, 1385 )
Approve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1387 async def deny_all_pending_group_users( 1388 self, 1389 access_token: str, 1390 /, 1391 group_id: int, 1392 *, 1393 message: str | None = None, 1394 ) -> None: 1395 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1396 await self._request( 1397 RequestMethod.POST, 1398 f"GroupV2/{group_id}/Members/DenyAll", 1399 auth=access_token, 1400 json={"message": str(message)}, 1401 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1403 async def add_optional_conversation( 1404 self, 1405 access_token: str, 1406 /, 1407 group_id: int, 1408 *, 1409 name: str | None = None, 1410 security: typing.Literal[0, 1] = 0, 1411 ) -> None: 1412 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1413 payload = {"chatName": str(name), "chatSecurity": security} 1414 await self._request( 1415 RequestMethod.POST, 1416 f"GroupV2/{group_id}/OptionalConversations/Add", 1417 json=payload, 1418 auth=access_token, 1419 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1421 async def edit_optional_conversation( 1422 self, 1423 access_token: str, 1424 /, 1425 group_id: int, 1426 conversation_id: int, 1427 *, 1428 name: str | None = None, 1429 security: typing.Literal[0, 1] = 0, 1430 enable_chat: bool = False, 1431 ) -> None: 1432 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1433 payload = { 1434 "chatEnabled": enable_chat, 1435 "chatName": str(name), 1436 "chatSecurity": security, 1437 } 1438 await self._request( 1439 RequestMethod.POST, 1440 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1441 json=payload, 1442 auth=access_token, 1443 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1445 async def transfer_item( 1446 self, 1447 access_token: str, 1448 /, 1449 item_id: int, 1450 item_hash: int, 1451 character_id: int, 1452 member_type: enums.MembershipType | int, 1453 *, 1454 stack_size: int = 1, 1455 vault: bool = False, 1456 ) -> None: 1457 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1458 payload = { 1459 "characterId": character_id, 1460 "membershipType": int(member_type), 1461 "itemId": item_id, 1462 "itemReferenceHash": item_hash, 1463 "stackSize": stack_size, 1464 "transferToVault": vault, 1465 } 1466 await self._request( 1467 RequestMethod.POST, 1468 "Destiny2/Actions/Items/TransferItem", 1469 json=payload, 1470 auth=access_token, 1471 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - vault (
bool): Whether to transfer this item to your vault or not. Defaults toFalse.
1473 async def pull_item( 1474 self, 1475 access_token: str, 1476 /, 1477 item_id: int, 1478 item_hash: int, 1479 character_id: int, 1480 member_type: enums.MembershipType | int, 1481 *, 1482 stack_size: int = 1, 1483 vault: bool = False, 1484 ) -> None: 1485 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1486 payload = { 1487 "characterId": character_id, 1488 "membershipType": int(member_type), 1489 "itemId": item_id, 1490 "itemReferenceHash": item_hash, 1491 "stackSize": stack_size, 1492 "transferToVault": vault, 1493 } 1494 await self._request( 1495 RequestMethod.POST, 1496 "Destiny2/Actions/Items/PullFromPostmaster", 1497 json=payload, 1498 auth=access_token, 1499 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - vault (
bool): Whether to pill this item to your vault or not. Defaults toFalse.
1501 async def fetch_fireteams( 1502 self, 1503 activity_type: fireteams.FireteamActivity | int, 1504 *, 1505 platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY, 1506 language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL, 1507 date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL, 1508 page: int = 0, 1509 slots_filter: int = 0, 1510 ) -> typedefs.JSONObject: 1511 resp = await self._request( 1512 RequestMethod.GET, 1513 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1514 ) 1515 assert isinstance(resp, dict) 1516 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
- platform (
aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1518 async def fetch_available_clan_fireteams( 1519 self, 1520 access_token: str, 1521 group_id: int, 1522 activity_type: fireteams.FireteamActivity | int, 1523 *, 1524 platform: fireteams.FireteamPlatform | int, 1525 language: fireteams.FireteamLanguage | str, 1526 date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL, 1527 page: int = 0, 1528 public_only: bool = False, 1529 slots_filter: int = 0, 1530 ) -> typedefs.JSONObject: 1531 resp = await self._request( 1532 RequestMethod.GET, 1533 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1534 json={"langFilter": str(language)}, 1535 auth=access_token, 1536 ) 1537 assert isinstance(resp, dict) 1538 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
- platform (
aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1540 async def fetch_clan_fireteam( 1541 self, access_token: str, fireteam_id: int, group_id: int 1542 ) -> typedefs.JSONObject: 1543 resp = await self._request( 1544 RequestMethod.GET, 1545 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1546 auth=access_token, 1547 ) 1548 assert isinstance(resp, dict) 1549 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1551 async def fetch_my_clan_fireteams( 1552 self, 1553 access_token: str, 1554 group_id: int, 1555 *, 1556 include_closed: bool = True, 1557 platform: fireteams.FireteamPlatform | int, 1558 language: fireteams.FireteamLanguage | str, 1559 filtered: bool = True, 1560 page: int = 0, 1561 ) -> typedefs.JSONObject: 1562 payload = {"groupFilter": filtered, "langFilter": str(language)} 1563 1564 resp = await self._request( 1565 RequestMethod.GET, 1566 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1567 json=payload, 1568 auth=access_token, 1569 ) 1570 assert isinstance(resp, dict) 1571 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1573 async def fetch_private_clan_fireteams( 1574 self, access_token: str, group_id: int, / 1575 ) -> int: 1576 resp = await self._request( 1577 RequestMethod.GET, 1578 f"Fireteam/Clan/{group_id}/ActiveCount", 1579 auth=access_token, 1580 ) 1581 assert isinstance(resp, int) 1582 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1584 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1585 resp = await self._request( 1586 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1587 ) 1588 assert isinstance(resp, dict) 1589 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1591 async def search_entities( 1592 self, name: str, entity_type: str, *, page: int = 0 1593 ) -> typedefs.JSONObject: 1594 resp = await self._request( 1595 RequestMethod.GET, 1596 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1597 json={"page": page}, 1598 ) 1599 assert isinstance(resp, dict) 1600 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1602 async def fetch_unique_weapon_history( 1603 self, 1604 membership_id: int, 1605 character_id: int, 1606 membership_type: enums.MembershipType | int, 1607 ) -> typedefs.JSONObject: 1608 resp = await self._request( 1609 RequestMethod.GET, 1610 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1611 ) 1612 assert isinstance(resp, dict) 1613 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1615 async def fetch_item( 1616 self, 1617 member_id: int, 1618 item_id: int, 1619 membership_type: enums.MembershipType | int, 1620 components: list[enums.ComponentType], 1621 ) -> typedefs.JSONObject: 1622 collector = _collect_components(components) 1623 1624 resp = await self._request( 1625 RequestMethod.GET, 1626 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1627 ) 1628 assert isinstance(resp, dict) 1629 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.aiobungie.MembershipType | int): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1631 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1632 resp = await self._request( 1633 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1634 ) 1635 assert isinstance(resp, dict) 1636 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1638 async def fetch_available_locales(self) -> typedefs.JSONObject: 1639 resp = await self._request( 1640 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1641 ) 1642 assert isinstance(resp, dict) 1643 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1645 async def fetch_common_settings(self) -> typedefs.JSONObject: 1646 resp = await self._request(RequestMethod.GET, "Settings") 1647 assert isinstance(resp, dict) 1648 return resp
Fetch the common settings used by Bungie's environment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1650 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1651 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1652 assert isinstance(resp, dict) 1653 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1655 async def fetch_global_alerts( 1656 self, *, include_streaming: bool = False 1657 ) -> typedefs.JSONArray: 1658 resp = await self._request( 1659 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1660 ) 1661 assert isinstance(resp, list) 1662 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1664 async def awainitialize_request( 1665 self, 1666 access_token: str, 1667 type: typing.Literal[0, 1], 1668 membership_type: enums.MembershipType | int, 1669 /, 1670 *, 1671 affected_item_id: int | None = None, 1672 character_id: int | None = None, 1673 ) -> typedefs.JSONObject: 1674 body = {"type": type, "membershipType": int(membership_type)} 1675 1676 if affected_item_id is not None: 1677 body["affectedItemId"] = affected_item_id 1678 1679 if character_id is not None: 1680 body["characterId"] = character_id 1681 1682 resp = await self._request( 1683 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1684 ) 1685 assert isinstance(resp, dict) 1686 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.aiobungie.MembershipType | int): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
int | None): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
int | None): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1688 async def awaget_action_token( 1689 self, access_token: str, correlation_id: str, / 1690 ) -> typedefs.JSONObject: 1691 resp = await self._request( 1692 RequestMethod.POST, 1693 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1694 auth=access_token, 1695 ) 1696 assert isinstance(resp, dict) 1697 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1717 async def fetch_vendors( 1718 self, 1719 access_token: str, 1720 character_id: int, 1721 membership_id: int, 1722 membership_type: enums.MembershipType | int, 1723 /, 1724 components: list[enums.ComponentType], 1725 filter: int | None = None, 1726 ) -> typedefs.JSONObject: 1727 components_ = _collect_components(components) 1728 route = ( 1729 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1730 f"/Character/{character_id}/Vendors/?components={components_}" 1731 ) 1732 1733 if filter is not None: 1734 route = route + f"&filter={filter}" 1735 1736 resp = await self._request( 1737 RequestMethod.GET, 1738 route, 1739 auth=access_token, 1740 ) 1741 assert isinstance(resp, dict) 1742 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1744 async def fetch_vendor( 1745 self, 1746 access_token: str, 1747 character_id: int, 1748 membership_id: int, 1749 membership_type: enums.MembershipType | int, 1750 vendor_hash: int, 1751 /, 1752 components: list[enums.ComponentType], 1753 ) -> typedefs.JSONObject: 1754 components_ = _collect_components(components) 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 ( 1758 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1759 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1760 ), 1761 auth=access_token, 1762 ) 1763 assert isinstance(resp, dict) 1764 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1766 async def fetch_application_api_usage( 1767 self, 1768 access_token: str, 1769 application_id: int, 1770 /, 1771 *, 1772 start: datetime.datetime | None = None, 1773 end: datetime.datetime | None = None, 1774 ) -> typedefs.JSONObject: 1775 end_date, start_date = time.parse_date_range(end, start) 1776 resp = await self._request( 1777 RequestMethod.GET, 1778 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1779 auth=access_token, 1780 ) 1781 assert isinstance(resp, dict) 1782 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
datetime.datetime | None): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
datetime.datetime | None): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10),
end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1784 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1785 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1786 assert isinstance(resp, list) 1787 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1794 async def fetch_content_by_id( 1795 self, id: int, locale: str, /, *, head: bool = False 1796 ) -> typedefs.JSONObject: 1797 resp = await self._request( 1798 RequestMethod.GET, 1799 f"Content/GetContentById/{id}/{locale}/", 1800 json={"head": head}, 1801 ) 1802 assert isinstance(resp, dict) 1803 return resp
1805 async def fetch_content_by_tag_and_type( 1806 self, locale: str, tag: str, type: str, *, head: bool = False 1807 ) -> typedefs.JSONObject: 1808 resp = await self._request( 1809 RequestMethod.GET, 1810 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1811 json={"head": head}, 1812 ) 1813 assert isinstance(resp, dict) 1814 return resp
1816 async def search_content_with_text( 1817 self, 1818 locale: str, 1819 /, 1820 content_type: str, 1821 search_text: str, 1822 tag: str, 1823 *, 1824 page: int | None = None, 1825 source: str | None = None, 1826 ) -> typedefs.JSONObject: 1827 body: typedefs.JSONObject = { 1828 "locale": locale, 1829 "currentpage": page or 1, 1830 "ctype": content_type, 1831 "searchtxt": search_text, 1832 "ctype": content_type, 1833 "searchtext": search_text, 1834 "tag": tag, 1835 "source": source, 1836 } 1837 1838 resp = await self._request(RequestMethod.GET, "Content/Search", params=body) 1839 assert isinstance(resp, dict) 1840 return resp
1842 async def search_content_by_tag_and_type( 1843 self, 1844 locale: str, 1845 tag: str, 1846 type: str, 1847 *, 1848 page: int | None = None, 1849 ) -> typedefs.JSONObject: 1850 body: typedefs.JSONObject = {"currentpage": page or 1} 1851 1852 resp = await self._request( 1853 RequestMethod.GET, 1854 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 1855 params=body, 1856 ) 1857 assert isinstance(resp, dict) 1858 return resp
1869 async def fetch_topics_page( 1870 self, 1871 category_filter: int, 1872 group: int, 1873 date_filter: int, 1874 sort: str | bytes, 1875 *, 1876 page: int | None = None, 1877 locales: collections.Iterable[str] | None = None, 1878 tag_filter: str | None = None, 1879 ) -> typedefs.JSONObject: 1880 params = { 1881 "locales": ",".join(locales) if locales is not None else "en", 1882 } 1883 if tag_filter: 1884 params["tagstring"] = tag_filter 1885 1886 resp = await self._request( 1887 RequestMethod.GET, 1888 f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/", 1889 params=params, 1890 ) 1891 assert isinstance(resp, dict) 1892 return resp
1894 async def fetch_core_topics_page( 1895 self, 1896 category_filter: int, 1897 date_filter: int, 1898 sort: str | bytes, 1899 *, 1900 page: int | None = None, 1901 locales: collections.Iterable[str] | None = None, 1902 ) -> typedefs.JSONObject: 1903 resp = await self._request( 1904 RequestMethod.GET, 1905 f"Forum/GetCoreTopicsPaged/{page or 0}" 1906 f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}", 1907 ) 1908 assert isinstance(resp, dict) 1909 return resp
1911 async def fetch_posts_threaded_page( 1912 self, 1913 parent_post: bool, 1914 page: int, 1915 page_size: int, 1916 parent_post_id: int, 1917 reply_size: int, 1918 root_thread_mode: bool, 1919 sort_mode: int, 1920 show_banned: str | None = None, 1921 ) -> typedefs.JSONObject: 1922 resp = await self._request( 1923 RequestMethod.GET, 1924 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 1925 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 1926 json={"showbanned": show_banned}, 1927 ) 1928 assert isinstance(resp, dict) 1929 return resp
1931 async def fetch_posts_threaded_page_from_child( 1932 self, 1933 child_id: bool, 1934 page: int, 1935 page_size: int, 1936 reply_size: int, 1937 root_thread_mode: bool, 1938 sort_mode: int, 1939 show_banned: str | None = None, 1940 ) -> typedefs.JSONObject: 1941 resp = await self._request( 1942 RequestMethod.GET, 1943 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 1944 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 1945 json={"showbanned": show_banned}, 1946 ) 1947 assert isinstance(resp, dict) 1948 return resp
1950 async def fetch_post_and_parent( 1951 self, child_id: int, /, *, show_banned: str | None = None 1952 ) -> typedefs.JSONObject: 1953 resp = await self._request( 1954 RequestMethod.GET, 1955 f"Forum/GetPostAndParent/{child_id}/", 1956 json={"showbanned": show_banned}, 1957 ) 1958 assert isinstance(resp, dict) 1959 return resp
1961 async def fetch_posts_and_parent_awaiting( 1962 self, child_id: int, /, *, show_banned: str | None = None 1963 ) -> typedefs.JSONObject: 1964 resp = await self._request( 1965 RequestMethod.GET, 1966 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 1967 json={"showbanned": show_banned}, 1968 ) 1969 assert isinstance(resp, dict) 1970 return resp
2000 async def fetch_recommended_groups( 2001 self, 2002 access_token: str, 2003 /, 2004 *, 2005 date_range: int = 0, 2006 group_type: enums.GroupType | int = enums.GroupType.CLAN, 2007 ) -> typedefs.JSONArray: 2008 resp = await self._request( 2009 RequestMethod.POST, 2010 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2011 auth=access_token, 2012 ) 2013 assert isinstance(resp, list) 2014 return resp
2021 async def fetch_user_clan_invite_setting( 2022 self, 2023 access_token: str, 2024 /, 2025 membership_type: enums.MembershipType | int, 2026 ) -> bool: 2027 resp = await self._request( 2028 RequestMethod.GET, 2029 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2030 auth=access_token, 2031 ) 2032 assert isinstance(resp, bool) 2033 return resp
2035 async def fetch_banned_group_members( 2036 self, access_token: str, group_id: int, /, *, page: int = 1 2037 ) -> typedefs.JSONObject: 2038 resp = await self._request( 2039 RequestMethod.GET, 2040 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2041 auth=access_token, 2042 ) 2043 assert isinstance(resp, dict) 2044 return resp
2046 async def fetch_pending_group_memberships( 2047 self, access_token: str, group_id: int, /, *, current_page: int = 1 2048 ) -> typedefs.JSONObject: 2049 resp = await self._request( 2050 RequestMethod.GET, 2051 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2052 auth=access_token, 2053 ) 2054 assert isinstance(resp, dict) 2055 return resp
2057 async def fetch_invited_group_memberships( 2058 self, access_token: str, group_id: int, /, *, current_page: int = 1 2059 ) -> typedefs.JSONObject: 2060 resp = await self._request( 2061 RequestMethod.GET, 2062 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2063 auth=access_token, 2064 ) 2065 assert isinstance(resp, dict) 2066 return resp
2068 async def invite_member_to_group( 2069 self, 2070 access_token: str, 2071 /, 2072 group_id: int, 2073 membership_id: int, 2074 membership_type: enums.MembershipType | int, 2075 *, 2076 message: str | None = None, 2077 ) -> typedefs.JSONObject: 2078 resp = await self._request( 2079 RequestMethod.POST, 2080 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2081 auth=access_token, 2082 json={"message": str(message)}, 2083 ) 2084 assert isinstance(resp, dict) 2085 return resp
2087 async def cancel_group_member_invite( 2088 self, 2089 access_token: str, 2090 /, 2091 group_id: int, 2092 membership_id: int, 2093 membership_type: enums.MembershipType | int, 2094 ) -> typedefs.JSONObject: 2095 resp = await self._request( 2096 RequestMethod.POST, 2097 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2098 auth=access_token, 2099 ) 2100 assert isinstance(resp, dict) 2101 return resp
2108 async def fetch_historical_stats( 2109 self, 2110 character_id: int, 2111 membership_id: int, 2112 membership_type: enums.MembershipType | int, 2113 day_start: datetime.datetime, 2114 day_end: datetime.datetime, 2115 groups: list[enums.StatsGroupType | int], 2116 modes: collections.Sequence[enums.GameMode | int], 2117 *, 2118 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2119 ) -> typedefs.JSONObject: 2120 end, start = time.parse_date_range(day_end, day_start) 2121 resp = await self._request( 2122 RequestMethod.GET, 2123 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2124 json={ 2125 "dayend": end, 2126 "daystart": start, 2127 "groups": [str(int(group)) for group in groups], 2128 "modes": [str(int(mode)) for mode in modes], 2129 "periodType": int(period_type), 2130 }, 2131 ) 2132 assert isinstance(resp, dict) 2133 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2135 async def fetch_historical_stats_for_account( 2136 self, 2137 membership_id: int, 2138 membership_type: enums.MembershipType | int, 2139 groups: list[enums.StatsGroupType | int], 2140 ) -> typedefs.JSONObject: 2141 resp = await self._request( 2142 RequestMethod.GET, 2143 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2144 json={"groups": [str(int(group)) for group in groups]}, 2145 ) 2146 assert isinstance(resp, dict) 2147 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2149 async def fetch_aggregated_activity_stats( 2150 self, 2151 character_id: int, 2152 membership_id: int, 2153 membership_type: enums.MembershipType | int, 2154 /, 2155 ) -> typedefs.JSONObject: 2156 resp = await self._request( 2157 RequestMethod.GET, 2158 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2159 f"Character/{character_id}/Stats/AggregateActivityStats/", 2160 ) 2161 assert isinstance(resp, dict) 2162 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
2164 async def equip_loadout( 2165 self, 2166 access_token: str, 2167 /, 2168 loadout_index: int, 2169 character_id: int, 2170 membership_type: enums.MembershipType | int, 2171 ) -> None: 2172 response = await self._request( 2173 RequestMethod.POST, 2174 "Destiny2/Actions/Loadouts/EquipLoadout/", 2175 json={ 2176 "loadoutIndex": loadout_index, 2177 "characterId": character_id, 2178 "membership_type": int(membership_type), 2179 }, 2180 auth=access_token, 2181 ) 2182 assert isinstance(response, int)
Equip a loadout. Your character must be in a Social space, Orbit or Offline while performing this operation.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
2184 async def snapshot_loadout( 2185 self, 2186 access_token: str, 2187 /, 2188 loadout_index: int, 2189 character_id: int, 2190 membership_type: enums.MembershipType | int, 2191 *, 2192 color_hash: int | None = None, 2193 icon_hash: int | None = None, 2194 name_hash: int | None = None, 2195 ) -> None: 2196 response = await self._request( 2197 RequestMethod.POST, 2198 "Destiny2/Actions/Loadouts/SnapshotLoadout/", 2199 auth=access_token, 2200 json={ 2201 "colorHash": color_hash, 2202 "iconHash": icon_hash, 2203 "nameHash": name_hash, 2204 "loadoutIndex": loadout_index, 2205 "characterId": character_id, 2206 "membershipType": int(membership_type), 2207 }, 2208 ) 2209 assert isinstance(response, int)
Snapshot a loadout with the currently equipped items.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
- color_hash (
int | None): ... - icon_hash (
int | None): ... - name_hash (
int | None): ...
2211 async def update_loadout( 2212 self, 2213 access_token: str, 2214 /, 2215 loadout_index: int, 2216 character_id: int, 2217 membership_type: enums.MembershipType | int, 2218 *, 2219 color_hash: int | None = None, 2220 icon_hash: int | None = None, 2221 name_hash: int | None = None, 2222 ) -> None: 2223 response = await self._request( 2224 RequestMethod.POST, 2225 "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/", 2226 auth=access_token, 2227 json={ 2228 "colorHash": color_hash, 2229 "iconHash": icon_hash, 2230 "nameHash": name_hash, 2231 "loadoutIndex": loadout_index, 2232 "characterId": character_id, 2233 "membershipType": int(membership_type), 2234 }, 2235 ) 2236 assert isinstance(response, int)
Update the loadout. Color, Icon and Name.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
- color_hash (
int | None): The new color hash of the loadout to update. - icon_hash (
int | None): The new icon hash of the loadout to update. - name_hash (
int | None): The new name hash of the loadout to update.
2238 async def clear_loadout( 2239 self, 2240 access_token: str, 2241 /, 2242 loadout_index: int, 2243 character_id: int, 2244 membership_type: enums.MembershipType | int, 2245 ) -> None: 2246 response = await self._request( 2247 RequestMethod.POST, 2248 "Destiny2/Actions/Loadouts/ClearLoadout/", 2249 json={ 2250 "loadoutIndex": loadout_index, 2251 "characterId": character_id, 2252 "membership_type": int(membership_type), 2253 }, 2254 auth=access_token, 2255 ) 2256 assert isinstance(response, int)
Clear the identifiers and items of a loadout.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
191class RESTPool: 192 """Pool of `RESTClient` instances. 193 194 This allows to create multiple instances of `RESTClient`s that can be acquired 195 which share the same TCP connector. 196 197 Example 198 ------- 199 ```py 200 import aiobungie 201 202 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 203 204 # Using a context manager to acquire an instance 205 # from the pool and close it after. 206 async with client_pool.acquire() as rest: 207 ... 208 ``` 209 210 Parameters 211 ---------- 212 token : `str` 213 A valid application token from Bungie's developer portal. 214 215 Other Parameters 216 ---------------- 217 max_retries : `int` 218 The max retries number to retry if the request hit a `5xx` status code. 219 client_secret : `str | None` 220 An optional application client secret, 221 This is only needed if you're fetching OAuth2 tokens with this client. 222 client_id : `int | None` 223 An optional application client id, 224 This is only needed if you're fetching OAuth2 tokens with this client. 225 enable_debugging : `bool | str` 226 Whether to enable logging responses or not. 227 228 Logging Levels 229 -------------- 230 * `False`: This will disable logging. 231 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 232 Like the response status, route, taken time and so on. 233 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 234 """ 235 236 __slots__ = ( 237 "_token", 238 "_max_retries", 239 "_client_secret", 240 "_client_id", 241 "_metadata", 242 "_enable_debug", 243 "_client_session", 244 "_loads", 245 "_dumps", 246 ) 247 248 # Looks like mypy doesn't like this. 249 if typing.TYPE_CHECKING: 250 _enable_debug: typing.Literal["TRACE"] | bool | int 251 252 def __init__( 253 self, 254 token: str, 255 /, 256 *, 257 client_secret: str | None = None, 258 client_id: int | None = None, 259 client_session: aiohttp.ClientSession | None = None, 260 dumps: typedefs.Dumps = helpers.dumps, 261 loads: typedefs.Loads = helpers.loads, 262 max_retries: int = 4, 263 enable_debugging: typing.Literal["TRACE"] | bool | int = False, 264 ) -> None: 265 self._client_secret = client_secret 266 self._client_id = client_id 267 self._token = token 268 self._max_retries = max_retries 269 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 270 self._enable_debug = enable_debugging 271 self._client_session = client_session 272 self._loads = loads 273 self._dumps = dumps 274 275 @property 276 def client_id(self) -> int | None: 277 return self._client_id 278 279 @property 280 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 281 """Pool's Metadata. This is different from client instance metadata.""" 282 return self._metadata 283 284 @typing.final 285 def acquire(self) -> RESTClient: 286 """Acquires a new `RESTClient` instance from this pool. 287 288 Returns 289 ------- 290 `RESTClient` 291 An instance of a `RESTClient`. 292 """ 293 return RESTClient( 294 self._token, 295 client_secret=self._client_secret, 296 client_id=self._client_id, 297 loads=self._loads, 298 dumps=self._dumps, 299 max_retries=self._max_retries, 300 enable_debugging=self._enable_debug, 301 client_session=self._client_session, 302 )
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same TCP connector.
Example
import aiobungie
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# from the pool and close it after.
async with client_pool.acquire() as rest:
...
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | TRACE: This will log the response headers along with the minimal information.
252 def __init__( 253 self, 254 token: str, 255 /, 256 *, 257 client_secret: str | None = None, 258 client_id: int | None = None, 259 client_session: aiohttp.ClientSession | None = None, 260 dumps: typedefs.Dumps = helpers.dumps, 261 loads: typedefs.Loads = helpers.loads, 262 max_retries: int = 4, 263 enable_debugging: typing.Literal["TRACE"] | bool | int = False, 264 ) -> None: 265 self._client_secret = client_secret 266 self._client_id = client_id 267 self._token = token 268 self._max_retries = max_retries 269 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 270 self._enable_debug = enable_debugging 271 self._client_session = client_session 272 self._loads = loads 273 self._dumps = dumps
Pool's Metadata. This is different from client instance metadata.
284 @typing.final 285 def acquire(self) -> RESTClient: 286 """Acquires a new `RESTClient` instance from this pool. 287 288 Returns 289 ------- 290 `RESTClient` 291 An instance of a `RESTClient`. 292 """ 293 return RESTClient( 294 self._token, 295 client_secret=self._client_secret, 296 client_id=self._client_id, 297 loads=self._loads, 298 dumps=self._dumps, 299 max_retries=self._max_retries, 300 enable_debugging=self._enable_debug, 301 client_session=self._client_session, 302 )
484@typing.final 485class Race(int, Enum): 486 """An Enum for Destiny races.""" 487 488 HUMAN = 0 489 AWOKEN = 1 490 EXO = 2 491 UNKNOWN = 3
An Enum for Destiny races.
132@typing.final 133class Raid(int, Enum): 134 """An Enum for all available raids in Destiny 2.""" 135 136 DSC = 910380154 137 """Deep Stone Crypt""" 138 139 LW = 2122313384 140 """Last Wish""" 141 142 VOG = 3881495763 143 """Normal Valut of Glass""" 144 145 GOS = 3458480158 146 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
251@attrs.define(auto_exc=True) 252class RateLimitedError(HTTPError): 253 """Raised when too many request status code is returned.""" 254 255 http_status: http.HTTPStatus = attrs.field( 256 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 257 ) 258 """The request response http status.""" 259 260 url: typedefs.StrOrURL 261 """The URL/endpoint caused this error.""" 262 263 body: typing.Any 264 """The response body.""" 265 266 retry_after: float = attrs.field(default=0.0) 267 """The amount of seconds you need to wait before retrying to requests.""" 268 269 message: str = attrs.field(init=False) 270 """A Bungie human readable message describes the cause of the error.""" 271 272 @message.default # type: ignore 273 def _(self) -> str: 274 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 275 276 def __str__(self) -> str: 277 return self.message
Raised when too many request status code is returned.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
47@typing.final 48class RecordState(enums.Flag): 49 """An enum for records component states.""" 50 51 NONE = 0 52 REDEEMED = 1 << 0 53 UNAVAILABLE = 1 << 1 54 OBJECTIVE_NOT_COMPLETED = 1 << 2 55 OBSCURED = 1 << 3 56 INVISIBLE = 1 << 4 57 ENTITLEMENT_UNOWNED = 1 << 5 58 CAN_EQUIP_TITLE = 1 << 6
An enum for records component states.
679@typing.final 680class Relationship(int, Enum): 681 """An enum for bungie friends relationship types.""" 682 683 UNKNOWN = 0 684 FRIEND = 1 685 INCOMING_REQUEST = 2 686 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
176class RequestMethod(str, enums.Enum): 177 """HTTP request methods enum.""" 178 179 GET = "GET" 180 """GET methods.""" 181 POST = "POST" 182 """POST methods.""" 183 PUT = "PUT" 184 """PUT methods.""" 185 PATCH = "PATCH" 186 """PATCH methods.""" 187 DELETE = "DELETE" 188 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
246@attrs.define(auto_exc=True) 247class ResponseError(HTTPException): 248 """Exception for other HTTP response errors."""
Exception for other HTTP response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
506@typing.final 507class Stat(int, Enum): 508 """An Enum for Destiny 2 character stats.""" 509 510 NONE = 0 511 MOBILITY = 2996146975 512 RESILIENCE = 392767087 513 RECOVERY = 1943323491 514 DISCIPLINE = 1735777505 515 INTELLECT = 144602215 516 STRENGTH = 4244567218 517 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
621@typing.final 622class TierType(int, Enum): 623 """An enum for a Destiny 2 item tier type.""" 624 625 UNKNOWN = 0 626 CURRENCY = 1 627 BASIC = 2 628 COMMON = 3 629 RARE = 4 630 SUPERIOR = 5 631 EXOTIC = 6
An enum for a Destiny 2 item tier type.
731@typing.final 732class TransferStatus(Flag): 733 """An enum for items transfer statuses.""" 734 735 CAN_TRANSFER = 0 736 """The item can be transferred.""" 737 IS_EQUIPPED = 1 << 0 738 """You can't transfer since the item is equipped.""" 739 NOT_TRASNFERRABLE = 1 << 1 740 """This item can not be transferred.""" 741 COULD_BE_TRANSFERRED = 1 << 2 742 """You can transfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can transfer the item. But the place you're trying to put it at has no space for it.
74@typing.final 75class ValueUIStyle(int, enums.Enum): 76 AUTOMATIC = 0 77 FRACTION = 1 78 CHECK_BOX = 2 79 PERCENTAGE = 3 80 DATETIME = 4 81 FRACTION_FLOAT = 5 82 INTEGER = 6 83 TIME_DURATION = 7 84 HIDDEN = 8 85 MULTIPLIER = 9 86 GREEN_PIPS = 10 87 RED_PIPS = 11 88 EXPLICIT_PERCENTAGE = 12 89 RAW_FLOAT = 13 90 LEVEL_AND_REWARD = 14
An enumeration.
229@typing.final 230class Vendor(int, Enum): 231 """An Enum for all available vendors in Destiny 2.""" 232 233 ZAVALA = 69482069 234 XUR = 2190858386 235 BANSHE = 672118013 236 SPIDER = 863940356 237 SHAXX = 3603221665 238 KADI = 529635856 239 """Postmaster exo.""" 240 YUNA = 1796504621 241 """Asia servers only.""" 242 EVERVERSE = 3361454721 243 AMANDA = 460529231 244 """Amanda holiday""" 245 CROW = 3611983588 246 HAWTHORNE = 3347378076 247 ADA1 = 350061650 248 DRIFTER = 248695599 249 IKORA = 1976548992 250 SAINT = 765357505 251 """Saint-14""" 252 ERIS_MORN = 1616085565 253 SHAW_HAWN = 1816541247 254 """COSMODROME Guy""" 255 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
520@typing.final 521class WeaponType(int, Enum): 522 """Enums for The three Destiny Weapon Types""" 523 524 NONE = 0 525 KINETIC = 1498876634 526 ENERGY = 2465295065 527 POWER = 953998645
Enums for The three Destiny Weapon Types
584def iter( 585 iterable: collections.Iterable[Item], 586) -> Iterator[Item]: 587 """Transform an iterable into an flat iterator. 588 589 Example 590 ------- 591 ```py 592 sequence = [1,2,3] 593 for item in aiobungie.iter(sequence).reversed(): 594 print(item) 595 # 3 596 # 2 597 # 1 598 ``` 599 600 Parameters 601 ---------- 602 iterable: `typing.Iterable[Item]` 603 The iterable to convert. 604 605 Raises 606 ------ 607 `StopIteration` 608 If no elements are left in the iterator. 609 """ 610 return Iterator(iterable)
Transform an iterable into an flat iterator.
Example
sequence = [1,2,3]
for item in aiobungie.iter(sequence).reversed():
print(item)
# 3
# 2
# 1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
280async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 281 """Generates and raise exceptions on error responses.""" 282 283 # Not a JSON response, raise immediately. 284 285 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 286 # request with a dummy access token. I can't really do anything about this.. 287 if response.content_type != "application/json": 288 return HTTPError( 289 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 290 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 291 ) 292 293 body: collections.Mapping[str, typing.Any] = helpers.loads(await response.read()) # type: ignore 294 message: str = body.get("Message", "UNDEFINED_MESSAGE") 295 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 296 message_data: dict[str, str] = body.get("MessageData", {}) 297 throttle_seconds: int = body.get("ThrottleSeconds", 0) 298 error_code: int = body.get("ErrorCode", 0) 299 300 # Standard HTTP status. 301 match response.status: 302 case http.HTTPStatus.NOT_FOUND: 303 return NotFound( 304 message=message, 305 error_code=error_code, 306 throttle_seconds=throttle_seconds, 307 url=str(response.real_url), 308 body=body, 309 headers=response.headers, 310 error_status=error_status, 311 message_data=message_data, 312 ) 313 314 case http.HTTPStatus.FORBIDDEN: 315 return Forbidden( 316 message=message, 317 error_code=error_code, 318 throttle_seconds=throttle_seconds, 319 url=str(response.real_url), 320 body=body, 321 headers=response.headers, 322 error_status=error_status, 323 message_data=message_data, 324 ) 325 326 case http.HTTPStatus.UNAUTHORIZED: 327 return Unauthorized( 328 message=message, 329 error_code=error_code, 330 throttle_seconds=throttle_seconds, 331 url=str(response.real_url), 332 body=body, 333 headers=response.headers, 334 error_status=error_status, 335 message_data=message_data, 336 ) 337 338 case http.HTTPStatus.BAD_REQUEST: 339 # Membership needs to be alone. 340 if error_status == "InvalidParameters": 341 return MembershipTypeError( 342 message=message, 343 body=body, 344 headers=response.headers, 345 url=str(response.url), 346 membership_type=message_data["membershipType"], 347 required_membership=message_data["membershipInfo.membershipType"], 348 membership_id=int(message_data["membershipId"]), 349 ) 350 return BadRequest( 351 message=message, 352 body=body, 353 headers=response.headers, 354 url=str(response.url), 355 ) 356 case _: 357 status = http.HTTPStatus(response.status) 358 359 if 400 <= status < 500: 360 return ResponseError( 361 message=message, 362 error_code=error_code, 363 throttle_seconds=throttle_seconds, 364 url=str(response.real_url), 365 body=body, 366 headers=response.headers, 367 error_status=error_status, 368 message_data=message_data, 369 http_status=status, 370 ) 371 372 # Need to self handle ~5xx errors 373 elif 500 <= status < 600: 374 # No API key or method requires OAuth2 most likely. 375 if error_status in { 376 "ApiKeyMissingFromRequest", 377 "WebAuthRequired", 378 "ApiInvalidOrExpiredKey", 379 "AuthenticationInvalid", 380 "AuthorizationCodeInvalid", 381 }: 382 return Unauthorized( 383 message=message, 384 error_code=error_code, 385 throttle_seconds=throttle_seconds, 386 url=str(response.real_url), 387 body=body, 388 headers=response.headers, 389 error_status=error_status, 390 message_data=message_data, 391 ) 392 393 # Anything contains not found. 394 elif ( 395 "NotFound" in error_status 396 or error_status == "UserCannotFindRequestedUser" 397 ): 398 return NotFound( 399 message=message, 400 error_code=error_code, 401 throttle_seconds=throttle_seconds, 402 url=str(response.real_url), 403 body=body, 404 headers=response.headers, 405 error_status=error_status, 406 message_data=message_data, 407 ) 408 409 # Other 5xx errors. 410 else: 411 return InternalServerError( 412 message=message, 413 error_code=error_code, 414 throttle_seconds=throttle_seconds, 415 url=str(response.real_url), 416 body=body, 417 headers=response.headers, 418 error_status=error_status, 419 message_data=message_data, 420 http_status=status, 421 ) 422 # Something else. 423 else: 424 return HTTPException( 425 message=message, 426 error_code=error_code, 427 throttle_seconds=throttle_seconds, 428 url=str(response.real_url), 429 body=body, 430 headers=response.headers, 431 error_status=error_status, 432 message_data=message_data, 433 http_status=status, 434 )
Generates and raise exceptions on error responses.
437def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 438 return ( 439 "{ \n" 440 + "\n".join( # noqa: W503 441 f"{f' {key}'}: {value}" 442 if key not in ("Authorization", "X-API-KEY") 443 else f" {key}: REDACTED_TOKEN" 444 for key, value in headers.items() 445 ) 446 + "\n}" # noqa: W503 447 )